<jupyter_start><jupyter_text>Simulation of a PT-Series time-bin interferometerThis notebook allows a user to simulate Orca's time bin interferometer, consisting of a train of single photons that interfere with each other within one or more loops, producing a large superposition state with different photon numbers at the outputs. The interference is determined by a programmable beam splitter located at each loop, with reflectivity $\theta$.Figure 1: Architecture of a PT-Series device.This toolkit contains simulation code for a single-loop PT-Series. A single loop is a regime in which efficient classical simulation is possible, which allows us to demonstrate use cases involving several hundred photons.<jupyter_code># First, perform the relevant imports and navigate to the root folder
import os
import numpy as np
import time
from pprint import pprint

if os.getcwd()[-9:]=="notebooks":
    os.chdir("..")

from quantumqubo.tbi import TBISampler<jupyter_output><empty_output><jupyter_text>Simulation of three single photons in three modesWe inject three single photons into three consecutive modes of a single loop PT-Series, corresponding to state |111>. We assume that the reflectivity parameters for the beam splitter used in the PT-Series is fixed over the course of this experiment, with reflectivity parameters $\theta=\pi/6$. This means that each beam splitter transmits a photon with probability $\cos(\pi/6)^2$.Figure 2: Photonic circuit diagram of a single loop PT-Series with three input photons.The photonic circuit diagram corresponding to a single loop PT-Series device with these three input photons is shown in figure 2. In this figure, each input temporal mode is represented as a spatial mode, and the cascade of beam splitters, each with a parameter $\theta$, represents the action of the single loop with a reconfigurable beam splitter. Note that this circuit distributes three input photons among 4 output modes.<jupyter_code>n_photons = 3  # number of photons.
angle = np.pi/6  # Parameter that determines beam splitter reflectivity. Reflectivity is determined by cos(ANGLE)^2
n_samples = 1000

beam_splitter_angles = [angle]*n_photons  # 3 beam splitters with reflectivity parameters pi/6
input_state = [1]*n_photons  # input state is |111>

tbi = TBISampler()
samples = tbi.sample(input_state, beam_splitter_angles, n_samples=n_samples)

print("Samples are presented as state: counts. For example, (0,0,1,2): 100 means that output state |0012> was measured 100 times.")
pprint(samples)<jupyter_output><empty_output><jupyter_text>Sampling from different probability distributionsWith different beam splitter angles, we get different photon number statistics<jupyter_code>new_angle = np.pi/3
new_beam_splitter_angles = [new_angle]*n_photons  # 3 beam splitters with reflectivity pi/3

new_samples = tbi.sample(input_state, new_beam_splitter_angles, n_samples=n_samples)

print("Samples are presented as state: counts. For example, (0,0,1,2): 100 means that output state |0012> was measured 100 times.")
pprint(new_samples)<jupyter_output><empty_output><jupyter_text>Sampling from the output of a large input stateWe can use our simulator to efficiently sample from much larger states, with for example 1000 input photons<jupyter_code>n_photons = 1000
angle = np.pi/6

beam_splitter_angles = [angle]*n_photons
input_state = [1]*n_photons

tbi_sampler = TBISampler()
n_samples = 1000

# The first time we sample can take longer due to compiling numba code, so we draw a single sample first
tbi_sampler.sample(input_state, beam_splitter_angles, n_samples=1)

start = time.time()
results = tbi_sampler.sample(input_state, beam_splitter_angles, n_samples=n_samples)
print("{} samples of states with {} photons calculated in {:.2f} seconds!".format(n_samples, n_photons, time.time()-start))<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.06711758584807492, 'fraction_numerical': 0.01847034339229969, 'mean_word_length': 5.878354203935599, 'pattern_counts': {'":': 1, '<': 17, '<?xml version=': 0, '>': 21, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '4', 'dir': 'jupyter-structured-clean-dedup', 'id': '116920', 'license': 'Apache-2.0', 'n_tokens_mistral': 1138, 'n_tokens_neox': 1042, 'n_words': 456, 'path': 'tutorial_notebooks/ptseries_simulation.ipynb', 'repo_name': 'orcacomputing/quantumqubo', 'size': '3844'}