Skip to content

Commit

Permalink
[minor] add unit test for class Transmon, Transducer, FockDetector, F…
Browse files Browse the repository at this point in the history
…ockBeamSplitter2; delete custom_gate in Class Circuit; update comments and arguments
  • Loading branch information
caitaozhan committed Jan 3, 2025
1 parent 64b5661 commit 151886a
Show file tree
Hide file tree
Showing 13 changed files with 200 additions and 81 deletions.
4 changes: 4 additions & 0 deletions example/QuantumTransduction/ConversionProtocols.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@
OPTICAL_WAVELENGTH = 1550 # nm

def get_conversion_matrix(efficiency: float) -> Qobj:
"""
Args:
efficiency (float): transducer efficiency
"""
custom_gate_matrix = np.array([
[1, 0, 0, 0],
[0, math.sqrt(1 - efficiency), math.sqrt(efficiency), 0],
Expand Down
6 changes: 3 additions & 3 deletions example/QuantumTransduction/DirectConversion.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
from sequence.components.detector import FockDetector
from sequence.constants import KET0, KET1

from example.Transducer_Examples.ConversionProtocols import EmittingProtocol, UpConversionProtocol, DownConversionProtocol
from example.QuantumTransduction.ConversionProtocols import EmittingProtocol, UpConversionProtocol, DownConversionProtocol


# GENERAL
Expand Down Expand Up @@ -105,7 +105,7 @@ def __init__(self, name, timeline, node2):

# add receivers
transmon.add_receiver(transducer)
transducer.add_output([node2, detector])
transducer.add_outputs([node2, detector])

# emitting protocol and upconversion protocol
self.emitting_protocol = EmittingProtocol(self, name + ".emitting_protocol", timeline, transmon, transducer)
Expand Down Expand Up @@ -152,7 +152,7 @@ def __init__(self, name, timeline):
transducer.attach(self)
transducer.attach(self.counter)
self.set_first_component(self.transducer_name)
transducer.add_output([transmon, detector])
transducer.add_outputs([transmon, detector])

# down conversion protocol
self.downconversion_protocol = DownConversionProtocol(self, name + ".downconversion_protocol", timeline, transducer, transmon)
Expand Down
33 changes: 13 additions & 20 deletions example/QuantumTransduction/EntanglementSwapping.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ def trigger(self, detector, info):
state_list= [KET1, KET0]
TRANSMON_EFFICIENCY = 1


# Transducer
EFFICIENCY_UP = 0.5

Expand Down Expand Up @@ -80,7 +79,6 @@ def __init__(self, name, timeline, node2):
self.transmon0_name = name + ".transmon0"
transmon0 = Transmon(name=self.transmon0_name, owner=self, timeline=timeline, wavelengths=[MICROWAVE_WAVELENGTH, OPTICAL_WAVELENGTH], photon_counter=0, efficiency=1, photons_quantum_state= state_list)
self.add_component(transmon0)
self.set_first_component(self.transmon0_name)

self.transducer_name = name + ".transducer"
transducer = Transducer(name=self.transducer_name, owner=self, timeline=timeline, efficiency=EFFICIENCY_UP)
Expand All @@ -89,16 +87,14 @@ def __init__(self, name, timeline, node2):
transducer.photon_counter = 0
self.counter = Counter()
transducer.attach(self.counter)
self.set_first_component(self.transducer_name)

transmon0.add_receiver(transducer)

self.transmon_name = name + ".transmon"
transmon = Transmon(name=self.transmon_name, owner=self, timeline=timeline, wavelengths=[MICROWAVE_WAVELENGTH, OPTICAL_WAVELENGTH], photon_counter=0, efficiency=1, photons_quantum_state= state_list)
self.add_component(transmon)
self.set_first_component(self.transmon_name)

transducer.add_output([node2, transmon]) # NOTE node2 shouldn't be receiver, the quantum channel is skipped
transducer.add_outputs([node2, transmon]) # NOTE node2 shouldn't be receiver, the quantum channel is skipped

self.emitting_protocol = EmittingProtocol(self, name + ".emitting_protocol", timeline, transmon0, transducer)
self.upconversion_protocol = UpConversionProtocol(self, name + ".upconversion_protocol", timeline, transducer, node2, transmon)
Expand All @@ -119,14 +115,12 @@ def __init__(self, name, timeline, src_list: List[str]):
detector_name = name + ".detector1"
detector = FockDetector(detector_name, timeline, efficiency=0.25)
self.add_component(detector)
self.set_first_component(detector_name)

detector_name2 = name + ".detector2"
detector2 = FockDetector(detector_name2, timeline, efficiency=0.25)
self.add_component(detector2)
self.set_first_component(detector_name2)

fock_beam_splitter.add_output([detector, detector2])
fock_beam_splitter.add_outputs([detector, detector2])

self.counter = Counter()
self.counter2 = Counter()
Expand All @@ -146,14 +140,13 @@ def receive_photon(self, photon: Photon, src_list: List[str]):
runtime = 10e12
tl = Timeline(runtime)

nodoprimo_name = "Node1"
nodoterzo_name = "Node3"

src_list = [nodoprimo_name, nodoterzo_name]
node1_name = "Node1"
node3_name = "Node3"
src_list = [node1_name, node3_name]

node2 = EntangleNode("node2", tl, src_list)
node1 = SenderNode(nodoprimo_name, tl, node2)
node3 = SenderNode(nodoterzo_name, tl, node2)
node1 = SenderNode(node1_name, tl, node2)
node3 = SenderNode(node3_name, tl, node2)

qc1 = QuantumChannel("qc.node1.node2", tl, attenuation=ATTENUATION, distance=DISTANCE)
qc2 = QuantumChannel("qc.node1.node3", tl, attenuation=ATTENUATION, distance=DISTANCE)
Expand Down Expand Up @@ -222,22 +215,22 @@ def receive_photon(self, photon: Photon, src_list: List[str]):
event2 = Event(event_time0, process2)
tl.schedule(event2)

process1 = Process(node1.upconversion_protocol, "start", [Photon]) # the parameter shouldn't be a class, it should be an object
process1 = Process(node1.upconversion_protocol, "start", [Photon]) # NOTE the parameter shouldn't be a class, it should be an object
event_time1 = event_time0 + ENTANGLEMENT_GENERATION_DURATION
event1 = Event(event_time1, process1)
tl.schedule(event1)

process3 = Process(node3.upconversion_protocol, "start", [Photon])
process3 = Process(node3.upconversion_protocol, "start", [Photon]) # NOTE the parameter shouldn't be a class, it should be an object
event3 = Event(event_time1, process3)
tl.schedule(event3)

# Node 2
process4 = Process(node2.swapping_protocol, "start", [Photon])
process4 = Process(node2.swapping_protocol, "start", [Photon]) # NOTE the parameter shouldn't be a class, it should be an object
event_time4 = event_time1 + SWAPPING_DUARTION
event4 = Event(event_time4, process4)
tl.schedule(event4)

process5 = Process(node2.measure_protocol, "start", [Photon])
process5 = Process(node2.measure_protocol, "start", [Photon]) # NOTE the parameter shouldn't be a class, it should be an object
event_time5 = event_time4 + MEASURE_DURATION
event5 = Event(event_time5, process5)
tl.schedule(event5)
Expand Down Expand Up @@ -279,8 +272,8 @@ def receive_photon(self, photon: Photon, src_list: List[str]):
print(f"Percentage of Entangled detected by SPD real: {percentage_spd_real:.2f}%")


#Plot

# Plot

color_blu = '#0047AB'
color_red = '#FF0000'
Expand Down
12 changes: 2 additions & 10 deletions example/QuantumTransduction/SwappingProtocols.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,12 +75,12 @@ def __init__(self, own: Node, name: str, tl: Timeline, FockBS: FockBeamSplitter2
self.tl = tl
self.FockBS = FockBS

def start(self, photon: "Photon") -> None:
def start(self, photon: Photon) -> None:

receivers = self.FockBS._receivers
photon_count = self.FockBS.photon_counter

if photon_count == 1:
if photon_count == 1:
selected_receiver = random.choice(receivers)
selected_receiver.get(photon)
selected_receiver.get_2(photon)
Expand All @@ -98,7 +98,6 @@ def received_message(self, src: str, msg):




class Measure(Protocol):
def __init__(self, own: Node, name: str, tl: Timeline, FockBS: FockBeamSplitter2):
super().__init__(own, name)
Expand All @@ -113,7 +112,6 @@ def __init__(self, own: Node, name: str, tl: Timeline, FockBS: FockBeamSplitter2
self.detector_photon_counter_ideal = 0
self.spd_ideal= 0


def start(self, photon: Photon) -> None:

if self.FockBS._receivers[0].photon_counter == 1 or self.FockBS._receivers[1].photon_counter == 1:
Expand All @@ -140,7 +138,6 @@ def get_detector_photon_counter_ideal(self):
def get_spd_ideal(self):
return self.spd_ideal


def received_message(self, src: str, msg):
pass

Expand All @@ -163,7 +160,6 @@ def start(self, photon: Photon) -> None:

self.FockBS._receivers[0].set_efficiency(1)
self.FockBS._receivers[1].set_efficiency(1)


if photon_count == 1:
selected_receiver = random.choice(receivers)
Expand All @@ -179,7 +175,6 @@ def start(self, photon: Photon) -> None:




class MeasureIdeal(Protocol):
def __init__(self, own: Node, name: str, tl: Timeline, FockBS: FockBeamSplitter2):
super().__init__(own, name)
Expand All @@ -191,7 +186,6 @@ def __init__(self, own: Node, name: str, tl: Timeline, FockBS: FockBeamSplitter2
self.detector_photon_counter_ideal = 0
self.spd_ideal= 0


self.detector_photon_counter_real = 0
self.spd_real= 0

Expand All @@ -202,14 +196,12 @@ def start(self, photon: Photon) -> None:

if self.FockBS._receivers[0].photon_counter >= 1 or self.FockBS._receivers[1].photon_counter >= 1:
self.spd_real += 1


print(f"Ideal detector photon counter: {self.detector_photon_counter_ideal}")
print(f"Ideal SPD: {self.spd_ideal}")

print(f"Detector photon counter with eta NOT 1 : {self.entanglement_count_real}")
print(f"SPD with eta NOT 1: {self.spd_real}")


def received_message(self, src: str, msg):
pass
26 changes: 18 additions & 8 deletions sequence/components/beam_splitter.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,30 +125,40 @@ def get(self, photon, **kwargs) -> None:
class FockBeamSplitter2(Entity):
"""Class modeling a Fock beam splitter. The '2' for avoiding naming conflicts.
A Fock beam splitter can send a single photon randomly in one of its ports.
A Fock beam splitter can send a single photon randomly in one of its ports.
See https://arxiv.org/abs/2411.11377, Simulation of Quantum Transduction Strategies for Quantum Networks
Attributes:
name (str): the name
owner (Node): the owner
timeline (Timeline): the timeline
efficiency (float): the efficiency of the beamsplitter
photon_counter (int): counter for counting photons
src_list (str): a list of photon source names
"""
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: float, photon_counter: int, src_list: List[str]):
Entity.__init__(self, name, timeline)
self.name = name
self.owner = owner
self.timeline = timeline
self.efficiency = efficiency
self.photon_counter = photon_counter

self.src_list = src_list

def init(self):
assert len(self._receivers) == 2

def receive_photon_from_scr(self, photon: Photon, source: List[str]) -> None:
def receive_photon_from_src(self, photon: Photon, source: List[str]) -> None:
"""Receive photon from two end nodes"""
self.photon_counter += 1

def add_output(self, outputs: List):
def add_outputs(self, outputs: List):
"""Add outputs, i.e., receivers
Args:
outputs (list): a list of entities, i.e., detectors
"""
for i in outputs:
self.add_receiver(i)

def send_photon(self, receiver: Entity, photon: Photon) -> None:
receiver.get(self.name, photon)

24 changes: 1 addition & 23 deletions sequence/components/circuit.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,6 @@ def t_gate():
return Qobj(mat, dims=[[2], [2]])


def custom_gate(p: float):
mat = np.array([[1, 0, 0, 0],
[0, 1, 1 - p, 0],
[0, 0, p, 0],
[0, 0, 0, 1]])
return Qobj(mat, dims=[[2, 2], [2, 2]])


def validator(func):
def wrapper(self, *args, **kwargs):
for q in args:
Expand Down Expand Up @@ -98,8 +90,7 @@ def get_unitary_matrix(self) -> np.ndarray:
"Y": y_gate,
"Z": z_gate,
"S": s_gate,
"T": t_gate,
"CUSTOM": custom_gate}
"T": t_gate}
for gate in self.gates:
name, indices, arg = gate
if name == 'h':
Expand All @@ -122,8 +113,6 @@ def get_unitary_matrix(self) -> np.ndarray:
qc.add_gate('S', indices[0])
elif name == 'phase':
qc.add_gate('PHASEGATE', indices[0], arg_value=arg)
elif name == 'custom':
qc.add_gate('CUSTOM', indices, arg_value=arg)
else:
raise NotImplementedError
self._cache = gate_sequence_product(qc.propagators()).full()
Expand Down Expand Up @@ -251,17 +240,6 @@ def phase(self, qubit: int, theta: float):

self.gates.append(['phase', [qubit], theta])

@validator
def custom(self, qubit: int, p: float):
"""Method to apply custom gate on two qubits.
Args:
qubit (int): the index of qubit in the circuit.
p (float): parameter for custom gate
"""

self.gates.append(['custom', [qubit], p])

@validator
def measure(self, qubit: int):
"""Method to measure quantum bit into classical bit.
Expand Down
31 changes: 25 additions & 6 deletions sequence/components/detector.py
Original file line number Diff line number Diff line change
Expand Up @@ -623,8 +623,8 @@ class FockDetector(Detector):
timeline (Timeline): the simulation timeline
efficiency (float): the efficiency of the detector
wavelength (int): wave length in nm
photon_counter (int):
photon_counter2 (int):
photon_counter (int): counting photon for the non ideal detector
photon_counter2 (int): counting photon for the ideal detector
"""

def __init__(self, name: str, timeline: "Timeline", efficiency: float, wavelength: int = 0):
Expand All @@ -641,18 +641,37 @@ def init(self):
pass

def get(self, photon: Photon = None, **kwargs) -> None:
"""Not ideal detector, there is a chance for photon loss."""
"""Not ideal detector, there is a chance for photon loss.
Args:
photon (Photon): photon
"""
if random.random() < self.efficiency:
self.photon_counter += 1

def get_2(self, photon: Photon = None, **kwargs) -> None:
"""Ideal detector, no photon loss"""
"""Ideal detector, no photon loss
Args:
photon (Photon): photon
"""
self.photon_counter2 += 1

def set_efficiency(self, efficiency):
def set_efficiency(self, efficiency: float):
"""Set the efficiency of the fock detector.
Args:
efficiency (float): the efficiency of the detector
"""
self.efficiency = efficiency

def receive_photon(self, src: str, photon: "Photon") -> None:
def receive_photon(self, src: str, photon: Photon) -> None:
"""receive a photon
Args:
src (str): name of the source node
photon (Photon): photon
"""
if photon.wavelength == self.wavelength:
self.get(photon)
else:
Expand Down
Loading

0 comments on commit 151886a

Please # to comment.