From 0e74ef33775dc5ecf8e3e1adfc0ab1093a2e361f Mon Sep 17 00:00:00 2001 From: Caitao Zhan Date: Thu, 19 Dec 2024 23:07:31 -0600 Subject: [PATCH] [minor] fix the direct conversion quantum tranduction protocol --- Makefile | 8 +- .../ConversionProtocols.py | 40 ++-- .../Transducer_Examples/DirectConversion.py | 207 +++++++++--------- .../TransductionComponent.py | 71 +++--- requirements.txt | 10 +- sequence/topology/node.py | 5 + 6 files changed, 176 insertions(+), 165 deletions(-) diff --git a/Makefile b/Makefile index 50c3d7ec..3a59b169 100644 --- a/Makefile +++ b/Makefile @@ -1,17 +1,17 @@ all: jupyter setup: - pip3 install -r ./requirements.txt + pip install -r ./requirements.txt install: - pip3 install . + pip install . install_editable: - pip3 install --editable . --config-settings editable_mode=strict + pip install --editable . --config-settings editable_mode=strict jupyter: jupyter notebook ./example/two_node_eg.ipynb test: - pip3 install . + pip install . pytest ./tests \ No newline at end of file diff --git a/example/Transducer_Examples/ConversionProtocols.py b/example/Transducer_Examples/ConversionProtocols.py index 3b79594a..9c09bdc2 100644 --- a/example/Transducer_Examples/ConversionProtocols.py +++ b/example/Transducer_Examples/ConversionProtocols.py @@ -46,18 +46,17 @@ def get_conversion_matrix(efficiency: float) -> Qobj: class EmittingProtocol(Protocol): + """Protocol for emission of single microwave photon by transmon. + """ - "Protocol for emission of single microwave photon by transmon" - - def __init__(self, own: "Node", name: str, tl: "Timeline", transmon="Transmon", transducer="Transducer"): - super().__init__(own, name) - self.owner = own + def __init__(self, owner: "Node", name: str, tl: "Timeline", transmon="Transmon", transducer="Transducer"): + super().__init__(owner, name) + self.owner = owner self.name = name self.tl = tl self.transmon = transmon self.transducer = transducer - def start(self) -> None: self.transmon.get() @@ -68,26 +67,24 @@ def start(self) -> None: self.transmon.photon_counter += 1 else: pass - else: - print("The transmon is in the state 00, or 01, it doesn't emit microwave photons") + print("The transmon is in the state 00, or 01, it doesn't emit microwave photons") print(f"Microwave photons emitted by the Transmon at Tx: {self.transmon.photon_counter}") - def received_message(self, src: str, msg): pass class UpConversionProtocol(Protocol): + """Protocol for Up-conversion of an input microwave photon into an output optical photon. + """ - "Protocol for Up-conversion of an input microwave photon into an output optical photon" - - def __init__(self, own: "Node", name: str, tl: "Timeline", transducer: "Transducer", node: "Node", transmon: "Transmon"): - super().__init__(own, name) - self.owner = own + def __init__(self, owner: "Node", name: str, tl: "Timeline", transducer: "Transducer", node: "Node", transmon: "Transmon"): + super().__init__(owner, name) + self.owner = owner self.name = name self.tl = tl self.transducer = transducer @@ -95,8 +92,7 @@ def __init__(self, own: "Node", name: str, tl: "Timeline", transducer: "Transduc self.node = node def start(self, photon: "Photon") -> None: - - + """start the protocol""" if self.transducer.photon_counter > 0: custom_gate = get_conversion_matrix(self.transducer.efficiency) @@ -127,20 +123,20 @@ def received_message(self, src: str, msg): class DownConversionProtocol(Protocol): + """Protocol for Down-conversion of an input optical photon into an output microwave photon. + """ - "Protocol for Down-conversion of an input optical photon into an output microwave photon" - - def __init__(self, own: "Node", name: str, tl: "Timeline", transducer: "Transducer", transmon: "Transmon"): - super().__init__(own, name) - self.owner = own + def __init__(self, owner: "Node", name: str, tl: "Timeline", transducer: "Transducer", transmon: "Transmon"): + super().__init__(owner, name) + self.owner = owner self.name = name self.tl = tl self.transducer = transducer def start(self, photon: "Photon") -> None: + """start the protocol""" if self.transducer.photon_counter > 0: - transducer_state = [0.0 + 0.0j, 0.0 + 0.0j, 1.0 + 0.0j, 0.0 + 0.0j] custom_gate = get_conversion_matrix(self.transducer.efficiency) diff --git a/example/Transducer_Examples/DirectConversion.py b/example/Transducer_Examples/DirectConversion.py index 6f2d89ba..bd67a4fc 100644 --- a/example/Transducer_Examples/DirectConversion.py +++ b/example/Transducer_Examples/DirectConversion.py @@ -1,31 +1,23 @@ +import sys +print(sys.path) +sys.path.append('.') + from sequence.kernel.timeline import Timeline from sequence.components.optical_channel import QuantumChannel -from sequence.protocol import Protocol from sequence.topology.node import Node -from sequence.components.light_source import LightSource -from sequence.utils.encoding import absorptive, single_atom from sequence.components.photon import Photon -from sequence.kernel.entity import Entity -from typing import List, Callable, TYPE_CHECKING -from abc import ABC, abstractmethod -from sequence.components.memory import Memory -from sequence.utils.encoding import fock -import math from sequence.kernel.event import Event from sequence.kernel.process import Process import sequence.utils.log as log import matplotlib.pyplot as plt -from example.Transducer_Examples.TransductionComponent import * +from example.Transducer_Examples.TransductionComponent import * from example.Transducer_Examples.ConversionProtocols import EmittingProtocol from example.Transducer_Examples.ConversionProtocols import UpConversionProtocol from example.Transducer_Examples.ConversionProtocols import DownConversionProtocol -from sequence.kernel.quantum_manager import QuantumManager -import sequence.components.circuit as Circuit - -#GENERAL +# GENERAL NUM_TRIALS = 50 FREQUENCY = 1e9 @@ -39,14 +31,14 @@ CONVERSION_DURATION = 10 # ps PERIOD = EMISSION_DURATION + CONVERSION_DURATION + CONVERSION_DURATION -#Transmon +# Transmon ket1 = (0.0 + 0.0j, 1.0 + 0.0j) ket0 = (1.0 + 0.0j, 0.0 + 0.0j) state_list= [ket1, ket0] TRANSMON_EFFICIENCY = 1 # Transducer -EFFICIENCY_UP = 0.5 +EFFICIENCY_UP = 0.5 EFFICIENCY_DOWN = 0.5 # Fock Detector @@ -60,85 +52,102 @@ +#NODES OF THE NETWORK +class SenderNode(Node): + """Sender node in the Direct Conversion Protocol. + A sender has three components: 1) transmon; 2) detector; 3) transducer -#NODES OF THE NETWORK - + Attributes: + name (str): name of the node + timeline (Timeline): timeline + transmon_name (str): name of the transmon + detector_name (str): name of the detector + transducer_name (str): name of the transducer -class SenderNode(Node): + """ def __init__(self, name, timeline, node2): super().__init__(name, timeline) - - #Hardware setup - + # transmon self.transmon_name = name + ".transmon" transmon = Transmon(name=self.transmon_name, owner=self, timeline=timeline, wavelength=[MICROWAVE_WAVELENGTH, OPTICAL_WAVELENGTH], photon_counter=0, efficiency=TRANSMON_EFFICIENCY, photons_quantum_state= state_list) self.add_component(transmon) - self.set_first_component(self.transmon_name) + # detector + detector_name = name + ".fockdetector" + detector = FockDetector(detector_name, timeline, wavelength=MICROWAVE_WAVELENGTH, efficiency=MICROWAVE_DETECTOR_EFFICIENCY_Tx) + self.add_component(detector) + self.counter = Counter() + detector.attach(self.counter) + # transducer self.transducer_name = name + ".transducer" transducer = Transducer(name=self.transducer_name, owner=self, timeline=timeline, efficiency=EFFICIENCY_UP) self.add_component(transducer) transducer.attach(self) - transducer.photon_counter = 0 self.counter = Counter() transducer.attach(self.counter) - self.set_first_component(self.transducer_name) - + # add receivers transmon.add_receiver(transducer) - - - detector_name = name + ".fockdetector1" - detector = FockDetector(detector_name, timeline, wavelength=MICROWAVE_WAVELENGTH, efficiency=MICROWAVE_DETECTOR_EFFICIENCY_Tx) - self.add_component(detector) - self.set_first_component(detector_name) - self.counter = Counter() - detector.attach(self.counter) - transducer.add_output([node2, detector]) - self.emitting_protocol = EmittingProtocol(self, name + ".emitting_protocol", timeline, transmon, transducer) + # emitting protocol and upconversion protocol + self.emitting_protocol = EmittingProtocol(self, name + ".emitting_protocol", timeline, transmon, transducer) self.upconversion_protocol = UpConversionProtocol(self, name + ".upconversion_protocol", timeline, transducer, node2, transmon) - class ReceiverNode(Node): + """Receiver node in the Direct Conversion Protocol. + + A receiver has three components: 1) transmon; 2) fock detector; 3) transducer + + Attributes: + name (str): name of the node + timeline (Timeline): the timeline + transmon_name (Transmon): name of the transmon + detector_name (str): name of the fock detector + counter2 (Counter): counter for the fock detector + transducer_name (str): name of the transducer + counter (Counter): counter for the transducer + downconversion_protocol (DownConversionProtocol): convert photon into microwave + """ def __init__(self, name, timeline): super().__init__(name, timeline) - self.transducer2_name = name + ".transducer2" - transducer2 = Transducer(name=self.transducer2_name, owner=self, timeline=timeline, efficiency=EFFICIENCY_DOWN) - self.add_component(transducer2) - transducer2.attach(self) - transducer2.photon_counter = 0 - self.counter = Counter() - transducer2.attach(self.counter) - self.set_first_component(self.transducer2_name) - - detector2_name = name + ".fockdetector2" - detector2 = FockDetector(detector2_name, timeline, wavelength=OPTICAL_WAVELENGTH, efficiency=OPTICAL_DETECTOR_EFFICIENCY) - self.add_component(detector2) + self.transmon_name = name + ".transmon" + self.detector_name = name + ".fockdetector" self.counter2 = Counter() - detector2.attach(self.counter2) + self.transducer_name = name + ".transducer" + self.counter = Counter() - self.transmon_name2 = name + ".transmon2" - transmon2 = Transmon(name=self.transmon_name2, owner=self, timeline=timeline, wavelength=[MICROWAVE_WAVELENGTH, OPTICAL_WAVELENGTH], photons_quantum_state= state_list, photon_counter=0, efficiency=1) - self.add_component(transmon2) - self.set_first_component(self.transmon_name2) + # transmon + transmon = Transmon(name=self.transmon_name, owner=self, timeline=timeline, wavelength=[MICROWAVE_WAVELENGTH, OPTICAL_WAVELENGTH], photons_quantum_state=state_list, photon_counter=0, efficiency=1) + self.add_component(transmon) - transducer2.add_output([transmon2,detector2]) - print(f"Transducer2 output: {transducer2._receivers}") + # fock detector + detector = FockDetector(self.detector_name, timeline, wavelength=OPTICAL_WAVELENGTH, efficiency=OPTICAL_DETECTOR_EFFICIENCY) + self.add_component(detector) + detector.attach(self.counter2) + + # transducer + transducer = Transducer(name=self.transducer_name, owner=self, timeline=timeline, efficiency=EFFICIENCY_DOWN) + self.add_component(transducer) + transducer.attach(self) + transducer.attach(self.counter) + self.set_first_component(self.transducer_name) + transducer.add_output([transmon, detector]) + + # down conversion protocol + self.downconversion_protocol = DownConversionProtocol(self, name + ".downconversion_protocol", timeline, transducer, transmon) - self.downconversion_protocol = DownConversionProtocol(self, name + ".downconversion_protocol", timeline, transducer2, transmon2) def receive_photon(self, src, photon): - self.components[self.transducer2_name].receive_photon_from_channel(photon) + self.components[self.transducer_name].receive_photon_from_channel(photon) #MAIN @@ -160,51 +169,50 @@ def receive_photon(self, src, photon): print("Error: the efficiency must be between 0 and 1") exit(1) - tl.init() - - total_photons_successful = 0 - total_transducer_count = 0 - - #Plot1 + # Plot1 failed_up_conversions = [] failed_down_conversions = [] successful_conversions = [] - #Plot2 + # Plot2 ideal_photons = [] emitted_photons = [] converted_photons = [] - + total_photons_successful = 0 + total_transducer_count = 0 cumulative_time = START_TIME - print(f"--------------------") + # Node1 + transmon1 = node1.get_components_by_type("Transmon")[0] + transducer1 = node1.get_components_by_type("Transducer")[0] + detector1 = node1.get_components_by_type("FockDetector")[0] + # Node2 + transmon2 = node2.get_components_by_type("Transmon")[0] + transducer2 = node2.get_components_by_type("Transducer")[0] + detector2 = node2.get_components_by_type("FockDetector")[0] + + print(f"--------------------") print(f"Direct Quantum Transduction Protocol starts, the qubit that we are going to convert is: {ket1}") for trial in range(NUM_TRIALS): print(f"--------------------") print(f"Trial {trial}:") + + # reset timeline + tl.time = 0 + tl.init() - tl.run() - - - #Node1 - transmon = node1.get_components_by_type("Transmon")[0] - transmon_count = transmon.photon_counter - transducer = node1.get_components_by_type("Transducer")[0] - transducer_count = transducer.photon_counter - detector = node1.get_components_by_type("FockDetector")[0] - detector_count = detector.photon_counter - - #Node2 - transducer2 = node2.get_components_by_type("Transducer")[0] - transmon2 = node2.get_components_by_type("Transmon")[0] - transmon2_count = transmon2.photon_counter - detector2 = node2.get_components_by_type("FockDetector")[0] - detector2_count = detector2.photon_counter + # Reset counters + transmon1.photon_counter = 0 + transducer1.photon_counter = 0 + detector1.photon_counter = 0 + transmon2.photon_counter = 0 + transducer2.photon_counter = 0 + detector2.photon_counter = 0 process0 = Process(node1.emitting_protocol, "start", []) event_time0 = (cumulative_time + EMISSION_DURATION) @@ -221,37 +229,26 @@ def receive_photon(self, src, photon): event2 = Event(event_time2, process2) tl.schedule(event2) - failed_up_conversions.append(detector_count) - failed_down_conversions.append(detector2_count) - successful_conversions.append(transmon2_count) + # run the simulation + tl.run() - print(f"Number of photons converted at time {tl.time}: {transmon2_count}") + # get the simulation results + failed_up_conversions.append(detector1.photon_counter) + failed_down_conversions.append(detector2.photon_counter) + successful_conversions.append(transmon2.photon_counter) - #reset timeline - tl.time = 0 - tl.init() - - total_photons_successful += transmon2_count - total_transducer_count += transducer_count + print(f"Number of photons converted at time {tl.time}: {transmon2.photon_counter}") + total_photons_successful += transmon2.photon_counter + total_transducer_count += transducer1.photon_counter cumulative_time += PERIOD ideal_photons.append(trial + 1) emitted_photons.append(total_transducer_count) converted_photons.append(total_photons_successful) - #Reset counters - transmon.photon_counter = 0 - transmon2.photon_counter = 0 - transducer.photon_counter = 0 - detector.photon_counter = 0 - detector2.photon_counter = 0 - transducer2.photon_counter = 0 - - - - #RESULTS + # RESULTS print(f"- - - - - - - - - -") print(f"Period: {PERIOD}") diff --git a/example/Transducer_Examples/TransductionComponent.py b/example/Transducer_Examples/TransductionComponent.py index fc31cab6..576c8ce0 100644 --- a/example/Transducer_Examples/TransductionComponent.py +++ b/example/Transducer_Examples/TransductionComponent.py @@ -33,24 +33,31 @@ def trigger(self, detector, info): self.count += 1 - class Transmon(Entity): - """Class modeling a transmon qubit. The Transmon class can be configured to emit microwave photons. + Attributes: + name (str): the name of the transmon + timeline (Timeline): the simulation timeline + owner (Node): the entity that owns or aggregates the current component + wavelengths (list): two wavelengths, one for microwave, and one for optics + photon_counter (int): photon counter + photongs_quantum_state (list): a list of quantum states + efficiency (float): the efficiency of the transmon """ - def __init__(self, owner: "Node", name: str, timeline: "Timeline", wavelength: List[int], photon_counter: int, photons_quantum_state: List[tuple], efficiency=1): + def __init__(self, owner: "Node", name: str, timeline: "Timeline", wavelength: List[int], photon_counter: int, photons_quantum_state: List[tuple], efficiency: float = 1): Entity.__init__(self, name, timeline) self.name = name self.owner = owner self.timeline = timeline + assert len(wavelength) == 2 self.wavelength = wavelength self.photon_counter = photon_counter self.photons_quantum_state = photons_quantum_state - self.efficiency=efficiency + self.efficiency = efficiency def init(self): pass @@ -61,22 +68,14 @@ def add_output(self, outputs: List): def get(self) -> None: - new_photon0 = Photon(name=self.name, - timeline=self.timeline, - wavelength=self.wavelength[0], - quantum_state=self.photons_quantum_state[0]) - - new_photon1 = Photon(name=self.name, - timeline=self.timeline, - wavelength=self.wavelength[1], - quantum_state=self.photons_quantum_state[1] - ) - + new_photon0 = Photon(name=self.name, timeline=self.timeline, wavelength=self.wavelength[0], quantum_state=self.photons_quantum_state[0]) + new_photon1 = Photon(name=self.name, timeline=self.timeline, wavelength=self.wavelength[1], quantum_state=self.photons_quantum_state[1]) + input_photons = [new_photon0, new_photon1] - input_quantum_state= np.kron(self.photons_quantum_state[0], self.photons_quantum_state[1]) + input_quantum_state = np.kron(self.photons_quantum_state[0], self.photons_quantum_state[1]) self.input_quantum_state = input_quantum_state - self.new_photon0=new_photon0 - self.new_photon1=new_photon1 + self.new_photon0 = new_photon0 + self.new_photon1 = new_photon1 def receive_photon_from_transducer(self, photon: "Photon") -> None: self.photon_counter += 1 @@ -86,26 +85,32 @@ def receive_photon(self, photon: "Photon") -> None: class Transducer(Entity): - """Class modeling a transducer. + A transducer can operate in two modes: up-conversion and down-conversion. In up-conversion it can convert microwave photons to optical photons. In down-conversion it can convert optical photons to microwave photons. + Attributes: + name (str): the name of the transducer + timeline (Timeline): the simulation timeline + owner (Node): the entity that owns or aggregates the current component + efficiency (float): the efficiency of the transducer + photon_counter (int): photon counter """ - def __init__(self, owner: "Node", name: str, timeline: "Timeline", efficiency=1, photon_counter=int): + def __init__(self, owner: "Node", name: str, timeline: "Timeline", efficiency: float = 1): Entity.__init__(self, name, timeline) self.name = name self.owner = owner self.timeline = timeline self.efficiency = efficiency - self.photon_counter = photon_counter + self.photon_counter = 0 - def init(self): assert len(self._receivers) == 2 def add_output(self, outputs: List): + """Add receivers""" for i in outputs: self.add_receiver(i) @@ -117,20 +122,27 @@ def receive_photon_from_channel(self, photon: "Photon") -> None: - class FockDetector(Detector): - """Class modeling a Fock detector. + A Fock detector can detect the number of photons in a given mode. + + Attributes: + name (str): name of the detector + timeline (Timeline): the simulation timeline + efficiency (float): the efficiency + wavelength (int): wave length in nm + photon_counter (int): + photon_counter2 (int): """ - def __init__(self, name: str, timeline: "Timeline", efficiency=1, wavelength=int, encoding_type=fock): + def __init__(self, name: str, timeline: "Timeline", efficiency: float, wavelength: int): super().__init__(name, timeline, efficiency) self.name = name self.photon_counter = 0 self.photon_counter2 = 0 self.wavelength = wavelength - self.encoding_type = encoding_type + self.encoding_type = fock self.timeline = timeline self.efficiency = efficiency @@ -147,7 +159,6 @@ def get_2(self, photon=None, **kwargs) -> None: def set_efficiency(self, efficiency): self.efficiency = efficiency - def receive_photon(self, src: str, photon: "Photon") -> None: if photon.wavelength == self.wavelength: self.get(photon) @@ -157,12 +168,14 @@ def receive_photon(self, src: str, photon: "Photon") -> None: class FockBeamSplitter(Entity): - """Class modeling a Fock beam splitter. + A Fock beam splitter can send a single photon randomly in one of its ports. + + """ - def __init__(self, name: str, owner: "Node", timeline: "Timeline", efficiency:int, photon_counter:int, src_list: List[str]): + def __init__(self, name: str, owner: "Node", timeline: "Timeline", efficiency: int, photon_counter: int, src_list: List[str]): Entity.__init__(self, name, timeline) self.name = name self.owner = owner diff --git a/requirements.txt b/requirements.txt index 42af6ebd..946967be 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,8 +1,8 @@ -numpy==2.2 -scipy==1.14.1 -qutip==5.0.4 -qutip-qip==0.4 -matplotlib +numpy>=2.1 +scipy>=1.14.1 +qutip>=5.0.4 +qutip-qip>=0.4 +matplotlib>=3.10 dash>=1.20.0 dash-core-components dash-html-components diff --git a/sequence/topology/node.py b/sequence/topology/node.py index 71c43b1d..4e994104 100644 --- a/sequence/topology/node.py +++ b/sequence/topology/node.py @@ -96,6 +96,11 @@ def add_component(self, component: Entity) -> None: component.owner = self def set_first_component(self, name: str): + """set the name of component that first receives incoming qubits. + + Args: + name (str): the name of component that first receives incoming qubits. + """ self.first_component_name = name def assign_cchannel(self, cchannel: "ClassicalChannel", another: str) -> None: