diff --git a/examples/stack/teleport/config.yaml b/examples/stack/teleport/config.yaml new file mode 100644 index 00000000..6326bd1c --- /dev/null +++ b/examples/stack/teleport/config.yaml @@ -0,0 +1,37 @@ +qdevice_cfg: &qdevice_cfg + num_qubits: 3 + num_comm_qubits: 1 + T1: 1.e+10 + T2: 1.e+9 + init_time: 1.e+4 + single_qubit_gate_time: 1.e+3 + two_qubit_gate_time: 1.e+5 + measurement_time: 1.e+4 + single_qubit_gate_depolar_prob: 0 + two_qubit_gate_depolar_prob: 0.01 + +stacks: + - name: sender + qdevice_typ: nv + qdevice_cfg: + <<: *qdevice_cfg + classical_cfg: + host_qnos_latency: 1e5 + - name: receiver + qdevice_typ: nv + qdevice_cfg: + <<: *qdevice_cfg + classical_cfg: + host_qnos_latency: 1e5 + +link_cfg: &link_cfg + fidelity: 0.8 + prob_success: 0.01 + t_cycle: 1.e+6 + +links: + - stack1: sender + stack2: receiver + typ: depolarise_any_bell + cfg: + <<: *link_cfg \ No newline at end of file diff --git a/examples/stack/teleport/example_teleport.py b/examples/stack/teleport/example_teleport.py index b9dd8a4f..2862b371 100644 --- a/examples/stack/teleport/example_teleport.py +++ b/examples/stack/teleport/example_teleport.py @@ -1,21 +1,20 @@ from __future__ import annotations -import math -from typing import Any, Dict, Generator +import os +from typing import Any, Dict, Generator, List -from netqasm.lang.ir import BreakpointAction, BreakpointRole +import netsquid as ns +from netqasm.lang.ir import BreakpointAction from netqasm.sdk.qubit import Qubit from netqasm.sdk.toolbox import set_qubit_state +from netsquid.qubits import operators, qubitapi from pydynaa import EventExpression -from squidasm.run.stack.config import ( - GenericQDeviceConfig, - LinkConfig, - StackConfig, - StackNetworkConfig, -) +from squidasm.run.stack.config import StackNetworkConfig from squidasm.run.stack.run import run +from squidasm.sim.stack.common import LogManager from squidasm.sim.stack.csocket import ClassicalSocket +from squidasm.sim.stack.globals import GlobalSimData from squidasm.sim.stack.program import Program, ProgramContext, ProgramMeta @@ -54,9 +53,6 @@ def run( set_qubit_state(q, self._phi, self._theta) e = epr_socket.create_keep()[0] - conn.insert_breakpoint( - BreakpointAction.DUMP_GLOBAL_STATE, BreakpointRole.CREATE - ) q.cnot(e) q.H() m1 = q.measure() @@ -93,9 +89,6 @@ def run( csocket: ClassicalSocket = context.csockets[self.PEER] e = epr_socket.recv_keep()[0] - conn.insert_breakpoint( - BreakpointAction.DUMP_GLOBAL_STATE, BreakpointRole.RECEIVE - ) yield from conn.flush() m1 = yield from csocket.recv_int() @@ -106,33 +99,54 @@ def run( if m1 == 1: e.Z() - # conn.insert_breakpoint(BreakpointAction.DUMP_LOCAL_STATE) + conn.insert_breakpoint(BreakpointAction.DUMP_LOCAL_STATE) + e.measure() yield from conn.flush() + all_states = GlobalSimData.get_last_breakpoint_state() + state = all_states["receiver"][0] + return state -if __name__ == "__main__": - # set_log_level("INFO") - sender_stack = StackConfig( - name="sender", - qdevice_typ="generic", - qdevice_cfg=GenericQDeviceConfig.perfect_config(), - ) - receiver_stack = StackConfig( - name="receiver", - qdevice_typ="generic", - qdevice_cfg=GenericQDeviceConfig.perfect_config(), +def do_teleportation( + cfg: StackNetworkConfig, + num_times: int = 1, + theta: float = 0.0, + phi: float = 0.0, + log_level: str = "WARNING", +) -> List[float]: + LogManager.set_log_level(log_level) + + sender_program = SenderProgram(theta=theta, phi=phi) + receiver_program = ReceiverProgram() + + _, final_states = run( + cfg, + {"sender": sender_program, "receiver": receiver_program}, + num_times=num_times, ) - link = LinkConfig( - stack1="sender", - stack2="receiver", - typ="perfect", + + expected = qubitapi.create_qubits(1)[0] + rot_theta = operators.create_rotation_op(theta, rotation_axis=(0, 1, 0)) + rot_phi = operators.create_rotation_op(phi, rotation_axis=(0, 0, 1)) + qubitapi.operate(expected, rot_theta) + qubitapi.operate(expected, rot_phi) + fidelities = [qubitapi.fidelity(expected, f, squared=True) for f in final_states] + + return fidelities + + +if __name__ == "__main__": + ns.set_qstate_formalism(ns.qubits.qformalism.QFormalism.DM) + + cfg = StackNetworkConfig.from_file( + os.path.join(os.getcwd(), os.path.dirname(__file__), "config.yaml") ) - cfg = StackNetworkConfig(stacks=[sender_stack, receiver_stack], links=[link]) + # link between sender and receiver + link = cfg.links[0] - sender_program = SenderProgram(theta=math.pi, phi=0) - receiver_program = ReceiverProgram() + link.cfg["fidelity"] = 0.8 - results = run(cfg, {"sender": sender_program, "receiver": receiver_program}) - print(results) + fidelities = do_teleportation(cfg, num_times=10, theta=0, phi=0) + print(fidelities) diff --git a/squidasm/run/stack/config.py b/squidasm/run/stack/config.py index 1ec04180..0087ee64 100644 --- a/squidasm/run/stack/config.py +++ b/squidasm/run/stack/config.py @@ -134,6 +134,16 @@ def from_file(cls, path: str) -> DepolariseLinkConfig: return _from_file(path, DepolariseLinkConfig) # type: ignore +class DepolariseAnyBellLinkConfig(BaseModel): + fidelity: float + prob_success: float + t_cycle: float + + @classmethod + def from_file(cls, path: str) -> DepolariseAnyBellLinkConfig: + return _from_file(path, DepolariseAnyBellLinkConfig) + + class NVLinkConfig(BaseModel): length_A: float length_B: float diff --git a/squidasm/run/stack/run.py b/squidasm/run/stack/run.py index 9770864d..fb51d665 100644 --- a/squidasm/run/stack/run.py +++ b/squidasm/run/stack/run.py @@ -4,6 +4,9 @@ from typing import Any, Dict, List import netsquid as ns +import numpy as np +from netsquid.qubits.ketstates import BellIndex +from netsquid.qubits.state_sampler import StateSampler from netsquid_magic.link_layer import ( MagicLinkLayerProtocol, MagicLinkLayerProtocolWithSignaling, @@ -12,13 +15,16 @@ from netsquid_magic.magic_distributor import ( DepolariseWithFailureMagicDistributor, DoubleClickMagicDistributor, + MagicDistributor, PerfectStateMagicDistributor, ) +from netsquid_magic.state_delivery_sampler import HeraldedStateDeliverySamplerFactory from netsquid_nv.magic_distributor import NVSingleClickMagicDistributor from netsquid_physlayer.heralded_connection import MiddleHeraldedConnection from squidasm.run.stack.build import build_generic_qdevice, build_nv_qdevice from squidasm.run.stack.config import ( + DepolariseAnyBellLinkConfig, DepolariseLinkConfig, GenericQDeviceConfig, HeraldedLinkConfig, @@ -32,6 +38,83 @@ from squidasm.sim.stack.stack import NodeStack, StackNetwork +class DepolariseWithFailureAnyBellStateSamplerFactory( + HeraldedStateDeliverySamplerFactory +): + """State sampler that samples any of the 4 Bell states with equal probablity.""" + + def __init__(self): + super().__init__(func_delivery=self._delivery_func) + + @staticmethod + def _delivery_func(prob_max_mixed, prob_success, **kwargs): + bell00 = np.array( + [[0.5, 0, 0, 0.5], [0, 0, 0, 0], [0, 0, 0, 0], [0.5, 0, 0, 0.5]], + dtype=np.complex, + ) + bell01 = np.array( + [[0, 0, 0, 0], [0, 0.5, 0.5, 0], [0, 0.5, 0.5, 0], [0, 0, 0, 0]], + dtype=np.complex, + ) + bell10 = np.array( + [[0, 0, 0, 0], [0, 0.5, -0.5, 0], [0, -0.5, 0.5, 0], [0, 0, 0, 0]], + dtype=np.complex, + ) + bell11 = np.array( + [[0.5, 0, 0, -0.5], [0, 0, 0, 0], [0, 0, 0, 0], [-0.5, 0, 0, 0.5]], + dtype=np.complex, + ) + maximally_mixed = np.array( + [[0.25, 0, 0, 0], [0, 0.25, 0, 0], [0, 0, 0.25, 0], [0, 0, 0, 0.25]], + dtype=np.complex, + ) + bell00_noisy = (1 - prob_max_mixed) * bell00 + prob_max_mixed * maximally_mixed + bell01_noisy = (1 - prob_max_mixed) * bell01 + prob_max_mixed * maximally_mixed + bell10_noisy = (1 - prob_max_mixed) * bell10 + prob_max_mixed * maximally_mixed + bell11_noisy = (1 - prob_max_mixed) * bell11 + prob_max_mixed * maximally_mixed + return ( + StateSampler( + qreprs=[bell00_noisy, bell01_noisy, bell10_noisy, bell11_noisy], + probabilities=[0.25, 0.25, 0.25, 0.25], + labels=[ + BellIndex.PHI_PLUS, + BellIndex.PSI_PLUS, + BellIndex.PSI_MINUS, + BellIndex.PHI_MINUS, + ], + ), + prob_success, + ) + + +class DepolariseWithFailureAnyBellMagicDistributor(MagicDistributor): + """Distributor that creates any of the 4 Bell states with equal probablity.""" + + def __init__(self, nodes, prob_max_mixed, prob_success, **kwargs): + self.prob_max_mixed = prob_max_mixed + self.prob_success = prob_success + super().__init__( + delivery_sampler_factory=DepolariseWithFailureAnyBellStateSamplerFactory(), + nodes=nodes, + **kwargs, + ) + + def add_delivery(self, memory_positions, **kwargs): + return super().add_delivery( + memory_positions=memory_positions, + prob_max_mixed=self.prob_max_mixed, + prob_success=self.prob_success, + **kwargs, + ) + + def get_bell_state(self, midpoint_outcome): + try: + status, label = midpoint_outcome + except ValueError: + raise ValueError("Unknown midpoint outcome {}".format(midpoint_outcome)) + return label + + def fidelity_to_prob_max_mixed(fid: float) -> float: return (1 - fid) * 4.0 / 3.0 @@ -80,6 +163,17 @@ def _setup_network(config: StackNetworkConfig) -> StackNetwork: prob_success=link_cfg.prob_success, t_cycle=link_cfg.t_cycle, ) + elif link.typ == "depolarise_any_bell": + link_cfg = link.cfg + if not isinstance(link_cfg, DepolariseAnyBellLinkConfig): + link_cfg = DepolariseAnyBellLinkConfig(**link.cfg) + prob_max_mixed = fidelity_to_prob_max_mixed(link_cfg.fidelity) + link_dist = DepolariseWithFailureAnyBellMagicDistributor( + nodes=[stack1.node, stack2.node], + prob_max_mixed=prob_max_mixed, + prob_success=link_cfg.prob_success, + t_cycle=link_cfg.t_cycle, + ) elif link.typ == "nv": link_cfg = link.cfg if not isinstance(link_cfg, NVLinkConfig):