Skip to content

Commit

Permalink
Work with Matheus and Kareem
Browse files Browse the repository at this point in the history
  • Loading branch information
SimonSekavcnik committed Feb 29, 2024
1 parent cf40375 commit 6b42383
Show file tree
Hide file tree
Showing 12 changed files with 285 additions and 38 deletions.
Empty file added examples/__init__.py
Empty file.
1 change: 1 addition & 0 deletions examples/custom_phase_shift/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from .custom_phase_shifter_device import CustomPhaseShift
38 changes: 38 additions & 0 deletions examples/custom_phase_shift/example.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
from .custom_phase_shifter_device import CustomPhaseShift


from quasi.simulation import Simulation, SimulationType, ModeManager
from quasi.devices.sources import IdealNPhotonSource, IdealCoherentSource
from quasi.devices.control import SimpleTrigger
from quasi.backend.fock_first_backend import FockBackendFirst
from quasi.signals import GenericBoolSignal, GenericQuantumSignal

import numpy as np
from math import pi
np.set_printoptions(suppress=True)
np.set_printoptions(linewidth=200)

sim = Simulation()
sim.set_backend(FockBackendFirst())
sim.set_dimensions(3)


S = IdealNPhotonSource("Source")
S.set_photon_num(1)
trigger = SimpleTrigger()

signals = {}
signals["trigger"] = GenericBoolSignal()
signals["qsig1"] = GenericQuantumSignal()

trigger.register_signal(signal=signals["trigger"], port_label="trigger")
S.register_signal(signal=signals["trigger"], port_label="trigger")

PS = CustomPhaseShift("Custom Phase Shift")
PS.set_params(pi/4, 1, 1, 0)

S.register_signal(signal=signals["qsig1"], port_label="output")
PS.register_signal(signal=signals["qsig1"], port_label="input")

state = exp.state
print(state.all_fock_probs())
107 changes: 107 additions & 0 deletions examples/custom_phase_shifter_device.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
from quasi.devices import (GenericDevice,
wait_input_compute,
coordinate_gui,
ensure_output_compute)
from quasi.devices.port import Port
from quasi.signals import (GenericSignal,
GenericFloatSignal,
GenericQuantumSignal)
from quasi.extra.logging import Loggers, get_custom_logger
from quasi.gui.icons import icon_list
from quasi.simulation import Simulation, SimulationType, ModeManager

logger = get_custom_logger(Loggers.Devices)

class CustomPhaseShift(GenericDevice):
"""
Implements Ideal Phase Shifter
"""

ports = {
"voltage": Port(label="voltage", direction="input", signal=None,
signal_type=GenericFloatSignal, device=None),
"A": Port(label="A", direction="input", signal=None,
signal_type=GenericFloatSignal, device=None),
"B": Port(label="B", direction="input", signal=None,
signal_type=GenericFloatSignal, device=None),
"C": Port(label="C", direction="input", signal=None,
signal_type=GenericFloatSignal, device=None),
"input": Port(label="input", direction="input", signal=None,
signal_type=GenericQuantumSignal, device=None),
"output": Port(label="output", direction="output", signal=None,
signal_type=GenericQuantumSignal, device=None)
}

gui_icon = icon_list.LASER
gui_tags = ["ideal"]
gui_name = "Ideal Coherent Photon Source"
gui_documentation = "ideal_phase_shifter.md"

power_peak = 0
power_average = 0
reference = None

def set_params(self, voltage, A, B, C):
"""
Sets the phi for the phase shifter
"""
sig_voltage = GenericFloatSignal()
sig_voltage.set_float(voltage)
self.register_signal(signal=sig_voltage, port_label="voltage")
sig_voltage.set_computed()

sig_A = GenericFloatSignal()
sig_A.set_float(A)
self.register_signal(signal=sig_A, port_label="A")
sig_A.set_computed()

sig_B = GenericFloatSignal()
sig_B.set_float(B)
self.register_signal(signal=sig_B, port_label="B")
sig_B.set_computed()

sig_C = GenericFloatSignal()
sig_C.set_float(C)
self.register_signal(signal=sig_C, port_label="C")
sig_C.set_computed()

@ensure_output_compute
@coordinate_gui
@wait_input_compute
def compute_outputs(self, *args, **kwargs):
simulation = Simulation.get_instance()
if simulation.simulation_type is SimulationType.FOCK:
self.simulate_fock()

def simulate_fock(self):
"""
Fock Simulation
"""
logger.info("Beam Splitter - %s - executing", self.name)
simulation = Simulation.get_instance()
backend = simulation.get_backend()

# Get the mode manager
mm = ModeManager()
# Generate new mode
mode = self.ports["input"].signal.mode_id
voltage = self.ports["voltage"].signal.contents
A = self.ports["A"].signal.contents
B = self.ports["B"].signal.contents
C = self.ports["C"].signal.contents


phi = A*voltage**B + C

# Initialize photon number state in the mode
operator = backend.phase_shift(phi, mm.get_mode_index(mode))
backend.apply_operator(operator, [mm.get_mode_index(mode)])

logger.info("Phase Shifter - %s - assisning mode %s to signal on port %s",
self.name, mm.get_mode_index(mode),
self.ports["output"].label)

self.ports["output"].signal.set_contents(
timestamp=0,
mode_id=mode)
self.ports["output"].signal.set_computed()
36 changes: 30 additions & 6 deletions examples/demo.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,25 @@
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"execution_count": 4,
"id": "1855e140",
"metadata": {},
"outputs": [],
"outputs": [
{
"ename": "ImportError",
"evalue": "cannot import name 'mean_photon' from 'quasi._math.fock' (/home/simon/Projects/QuaSi/quasi/_math/fock/__init__.py)",
"output_type": "error",
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[0;31mImportError\u001b[0m Traceback (most recent call last)",
"Cell \u001b[0;32mIn[4], line 6\u001b[0m\n\u001b[1;32m 4\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01mmath\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m pi\n\u001b[1;32m 5\u001b[0m \u001b[38;5;28;01mimport\u001b[39;00m \u001b[38;5;21;01mnumpy\u001b[39;00m \u001b[38;5;28;01mas\u001b[39;00m \u001b[38;5;21;01mnp\u001b[39;00m\n\u001b[0;32m----> 6\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01mquasi\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01m_math\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mfock\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m mean_photon\n",
"\u001b[0;31mImportError\u001b[0m: cannot import name 'mean_photon' from 'quasi._math.fock' (/home/simon/Projects/QuaSi/quasi/_math/fock/__init__.py)"
]
}
],
"source": [
"from quasi.simulation import Simulation\n",
"from quasi.experiement import Experiement\n",
"from quasi.experiment import Experiment\n",
"from quasi.components.gates import Squeezing, Beamsplitter, Phase\n",
"from math import pi\n",
"import numpy as np\n",
Expand All @@ -17,10 +29,22 @@
},
{
"cell_type": "code",
"execution_count": 2,
"execution_count": 1,
"id": "8d6b64f9",
"metadata": {},
"outputs": [],
"outputs": [
{
"ename": "NameError",
"evalue": "name 'Squeezing' is not defined",
"output_type": "error",
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)",
"Cell \u001b[0;32mIn[1], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m squeezing_gate \u001b[38;5;241m=\u001b[39m \u001b[43mSqueezing\u001b[49m(r\u001b[38;5;241m=\u001b[39m\u001b[38;5;241m1\u001b[39m, phi\u001b[38;5;241m=\u001b[39mpi, cutoff\u001b[38;5;241m=\u001b[39m\u001b[38;5;241m10\u001b[39m)\n\u001b[1;32m 3\u001b[0m bs_gate \u001b[38;5;241m=\u001b[39m Beamsplitter(theta\u001b[38;5;241m=\u001b[39mpi\u001b[38;5;241m/\u001b[39m\u001b[38;5;241m4\u001b[39m, phi\u001b[38;5;241m=\u001b[39m\u001b[38;5;241m0\u001b[39m, cutoff\u001b[38;5;241m=\u001b[39m\u001b[38;5;241m10\u001b[39m)\n\u001b[1;32m 5\u001b[0m phase_gate \u001b[38;5;241m=\u001b[39m Phase(phi\u001b[38;5;241m=\u001b[39mpi\u001b[38;5;241m/\u001b[39m\u001b[38;5;241m4\u001b[39m, cutoff\u001b[38;5;241m=\u001b[39m\u001b[38;5;241m10\u001b[39m)\n",
"\u001b[0;31mNameError\u001b[0m: name 'Squeezing' is not defined"
]
}
],
"source": [
"squeezing_gate = Squeezing(r=1, phi=pi, cutoff=10)\n",
"\n",
Expand Down Expand Up @@ -225,7 +249,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.10.12"
"version": "3.11.7"
}
},
"nbformat": 4,
Expand Down
62 changes: 51 additions & 11 deletions examples/mach_zender_bb84.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,15 @@
from quasi.signals import GenericBoolSignal, GenericQuantumSignal
from quasi.experiment import Experiment
from quasi.backend.fock_first_backend import FockBackendFirst
from quasi._math.fock import ops

# Import Custom Phase Shift
from custom_phase_shifter_device import CustomPhaseShift

import numpy as np
from math import pi

np.set_printoptions(suppress=True)
np.set_printoptions(linewidth=200)

sim = Simulation()
sim.set_backend(FockBackendFirst())
Expand All @@ -22,14 +28,15 @@
BSb = IdealBeamSplitter("BSb")
BSc = IdealBeamSplitter("BSc")
BSd = IdealBeamSplitter("BSd")

PSa = IdealPhaseShifter("PSa")
PSa.set_phi(pi/4)
#PSa = IdealPhaseShifter("PSa")
PSa = CustomPhaseShift("PSa")
PSa.set_params(voltage=pi/2, A=1, B=1, C=-pi/4)
#PSa.set_phi(pi/4)

PSb = IdealPhaseShifter("PSb")
PSb.set_phi(pi/2)
PSb.set_phi(pi/4)

S = IdealNPhotonSource()
S = IdealNPhotonSource("Source")
S.set_photon_num(1)
trigger = SimpleTrigger()

Expand All @@ -45,7 +52,7 @@
signals["qsig7"] = GenericQuantumSignal()
signals["qsig8"] = GenericQuantumSignal()
signals["qsig9"] = GenericQuantumSignal()

discard_sig = GenericQuantumSignal()
# Connect trigger and source
trigger.register_signal(signal=signals["trigger"], port_label="trigger")
S.register_signal(signal=signals["trigger"], port_label="trigger")
Expand All @@ -70,8 +77,10 @@
BSb.register_signal(signal=signals["qsig5"], port_label="C")
BSb.register_signal(signal=signals["qsig6"], port_label="D")

#BSb.register_signal(signal=signals["qsig6"], port_label="D")

BSc.register_signal(signal=signals["qsig5"], port_label="A")
BSc.register_signal(signal=signals["qsig6"], port_label="B")
#BSc.register_signal(signal=signals["qsig6"], port_label="B")


# Connect beamsplitter c and phase shifter
Expand All @@ -97,9 +106,40 @@

exp = Experiment.get_instance()

print(exp.state.all_fock_probs())
#print(exp.state.all_fock_probs())
state = exp.state
mm = ModeManager()

print(state.mean_photon(mode=[mm.get_mode_index(dsig1.mode_id)]))
print(state.mean_photon(mode=[mm.get_mode_index(dsig2.mode_id)]))
print("trace")
#print(ops.calculate_trace(state))

print(mm.get_mode_index(dsig1.mode_id))

m1 = state.mean_photon(mode=[mm.get_mode_index(dsig1.mode_id)])
m2 = state.mean_photon(mode=[mm.get_mode_index(dsig2.mode_id)])

print(f"Probability of measuring photon in det 1: {m1}")
print(f"Probability of measuring photon in det 1: {m2}")

det1 = mm.get_mode_index(dsig1.mode_id)
det2 = mm.get_mode_index(dsig2.mode_id)
disc = mm.get_mode_index(signals["qsig6"].mode_id)

p1 = [0,0,0]
p1[det1] = 1
p1[det2] = 0
p1[disc] = 0

p2 = [0,0,0]
p2[det1] = 0
p2[det2] = 0
p2[disc] = 1


print(det1, det2)
print(f"Probability |1,0,0>, |det1, det2, disc>")
print(state.all_fock_probs()[*p1])
print(f"Probability |0,0,1>, |det1, det2, disc>")
print(state.all_fock_probs()[*p2])
print(state.all_fock_probs())
print(state.dm().shape)
1 change: 1 addition & 0 deletions quasi/_math/fock/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from .ops import (
fock_operator,
displacement,
beamsplitter,
phase,
Expand Down
14 changes: 12 additions & 2 deletions quasi/_math/fock/ops.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from itertools import chain, product

import numpy as np
from numba import njit
from numba import njit, prange
from scipy.linalg import expm as matrixExp
from scipy.special import factorial
from quasi._math.states import FockState
Expand Down Expand Up @@ -99,6 +99,15 @@ def a(cutoff):

return np.diag(data, 1)

@njit
def fock_operator(n, cut):
op = adagger(cut)
if n == 1:
return op
else:
for _ in prange(n-1):
op = op @ op
return op

@njit
def adagger(cutoff):
Expand Down Expand Up @@ -354,6 +363,7 @@ def apply_gate_BLAS(mat, state, modes, n, trunc):
transpose_list + [2 * i for i in modes] + [2 * i + 1 for i in modes]
)
view = np.transpose(state, transpose_list)


# Apply matrix to each substate
ret = np.zeros([trunc for i in range(n * 2)], dtype=def_type)
Expand Down Expand Up @@ -438,7 +448,7 @@ def homodyne(state, phi, mode, hbar):
def calculate_trace(state):
eqn_indices = [[indices[idx]] * 2 for idx in range(state._num_modes)]
eqn = "".join(chain.from_iterable(eqn_indices))
return np.einsum(eqn, state).real
return np.einsum(eqn, state.dm()).real


def partial_trace(state, n, modes):
Expand Down
Loading

0 comments on commit 6b42383

Please sign in to comment.