def test_two_dimensional_cluster_denmark(): """ Two-dimensional temporal-mode cluster state as demonstrated in https://arxiv.org/pdf/1906.08709 """ np.random.seed(42) sq_r = 3 delay1 = 1 # number of timebins in the short delay line delay2 = 12 # number of timebins in the long delay line n = 200 # number of timebins shots = 10 # first half of cluster state measured in X, second half in P theta_A = [0] * int(n / 2) + [np.pi / 2] * int( n / 2) # measurement angles for detector A theta_B = theta_A # measurement angles for detector B # 2D cluster prog = tdmprogram.TDMProgram([1, delay2 + delay1 + 1]) with prog.context(theta_A, theta_B, shift="default") as (p, q): ops.Sgate(sq_r, 0) | q[0] ops.Sgate(sq_r, 0) | q[delay2 + delay1 + 1] ops.Rgate(np.pi / 2) | q[delay2 + delay1 + 1] ops.BSgate(np.pi / 4, np.pi) | (q[delay2 + delay1 + 1], q[0]) ops.BSgate(np.pi / 4, np.pi) | (q[delay2 + delay1], q[0]) ops.BSgate(np.pi / 4, np.pi) | (q[delay1], q[0]) ops.MeasureHomodyne(p[1]) | q[0] ops.MeasureHomodyne(p[0]) | q[delay1] eng = sf.Engine("gaussian") result = eng.run(prog, shots=shots) reshaped_samples = result.samples for sh in range(shots): X_A = reshaped_samples[sh][0][:n // 2] # X samples from detector A P_A = reshaped_samples[sh][0][n // 2:] # P samples from detector A X_B = reshaped_samples[sh][1][:n // 2] # X samples from detector B P_B = reshaped_samples[sh][1][n // 2:] # P samples from detector B # nullifiers defined in https://arxiv.org/pdf/1906.08709.pdf, Eqs. (1) and (2) N = delay2 ntot = len(X_A) - delay2 - 1 nX = np.array([ X_A[k] + X_B[k] - X_A[k + 1] - X_B[k + 1] - X_A[k + N] + X_B[k + N] - X_A[k + N + 1] + X_B[k + N + 1] for k in range(ntot) ]) nP = np.array([ P_A[k] + P_B[k] + P_A[k + 1] + P_B[k + 1] - P_A[k + N] + P_B[k + N] + P_A[k + N + 1] - P_B[k + N + 1] for k in range(ntot) ]) nXvar = np.var(nX) nPvar = np.var(nP) assert np.allclose(nXvar, 4 * sf.hbar * np.exp(-2 * sq_r), rtol=5 / np.sqrt(ntot)) assert np.allclose(nPvar, 4 * sf.hbar * np.exp(-2 * sq_r), rtol=5 / np.sqrt(ntot))
def test_one_dimensional_cluster_tokyo(): """ One-dimensional temporal-mode cluster state as demonstrated in https://aip.scitation.org/doi/pdf/10.1063/1.4962732 """ np.random.seed(42) sq_r = 5 n = 10 # for an n-mode cluster state shots = 3 # first half of cluster state measured in X, second half in P theta1 = [0] * int(n / 2) + [np.pi / 2] * int( n / 2) # measurement angles for detector A theta2 = theta1 # measurement angles for detector B prog = tdmprogram.TDMProgram(N=[1, 2]) with prog.context(theta1, theta2, shift="default") as (p, q): ops.Sgate(sq_r, 0) | q[0] ops.Sgate(sq_r, 0) | q[2] ops.Rgate(np.pi / 2) | q[0] ops.BSgate(np.pi / 4) | (q[0], q[2]) ops.BSgate(np.pi / 4) | (q[0], q[1]) ops.MeasureHomodyne(p[0]) | q[0] ops.MeasureHomodyne(p[1]) | q[1] eng = sf.Engine("gaussian") result = eng.run(prog, shots=shots) reshaped_samples = result.samples for sh in range(shots): X_A = reshaped_samples[sh][0][:n // 2] # X samples from detector A P_A = reshaped_samples[sh][0][n // 2:] # P samples from detector A X_B = reshaped_samples[sh][1][:n // 2] # X samples from detector B P_B = reshaped_samples[sh][1][n // 2:] # P samples from detector B # nullifiers defined in https://aip.scitation.org/doi/pdf/10.1063/1.4962732, Eqs. (1a) and (1b) ntot = len(X_A) - 1 nX = np.array( [X_A[i] + X_B[i] + X_A[i + 1] - X_B[i + 1] for i in range(ntot)]) nP = np.array( [P_A[i] + P_B[i] - P_A[i + 1] + P_B[i + 1] for i in range(ntot)]) nXvar = np.var(nX) nPvar = np.var(nP) assert np.allclose(nXvar, 2 * sf.hbar * np.exp(-2 * sq_r), rtol=5 / np.sqrt(n)) assert np.allclose(nPvar, 2 * sf.hbar * np.exp(-2 * sq_r), rtol=5 / np.sqrt(n))
def compile_test_program(device, args=(-1, 1, 2, 3)): """Compiles a test program with the given gate arguments.""" alpha = [args[1]] beta = [args[2]] gamma = [args[3]] prog = tdmprogram.TDMProgram(N=2) with prog.context(alpha, beta, gamma) as (p, q): ops.Sgate(args[0]) | q[ 1] # Note that the Sgate has a second parameter that is non-zero ops.Rgate(p[0]) | q[0] ops.BSgate(p[1]) | (q[0], q[1]) ops.MeasureHomodyne(p[2]) | q[0] prog.compile(device=device, compiler=device.compiler)
def test_passing_list_of_tdmprograms(self): """Test that error is raised when passing a list containing TDM programs""" prog = tdmprogram.TDMProgram(N=2) with prog.context([1, 1], [1, 1], [1, 1]) as (p, q): ops.Sgate(0, 0) | q[1] ops.BSgate(p[0]) | (q[0], q[1]) ops.Rgate(p[1]) | q[1] ops.MeasureHomodyne(p[2]) | q[0] eng = sf.Engine("gaussian") with pytest.raises( NotImplementedError, match="Lists of TDM programs are not currently supported"): eng.run([prog, prog])
def test_at_least_one_measurement(self): """Checks circuit has at least one measurement operator""" sq_r = 1.0 N = 3 shots = 1 alpha = [0] * 4 phi = [0] * 4 prog = tdmprogram.TDMProgram(N=N) with pytest.raises(ValueError, match="Must be at least one measurement."): with prog.context(alpha, phi, shift="default") as (p, q): ops.Sgate(sq_r, 0) | q[2] ops.BSgate(p[0]) | (q[1], q[2]) ops.Rgate(p[1]) | q[2] eng = sf.Engine("gaussian") eng.run(prog, shots=shots)
def test_tdm_wrong_modes(self): """Test the correct error is raised when the tdm circuit registers don't match the device spec""" sq_r = 0.5643 c = 2 alpha = [np.pi / 4, 0] * c phi = [0, np.pi / 2] * c theta = [0, 0] + [np.pi / 2, np.pi / 2] prog = tdmprogram.TDMProgram(N=2) with prog.context(alpha, phi, theta) as (p, q): ops.Sgate(sq_r) | q[1] ops.BSgate(p[0]) | (q[0], q[1]) # The order should be (q[1], q[0]) ops.Rgate(p[1]) | q[1] ops.MeasureHomodyne(p[2]) | q[0] eng = sf.Engine("gaussian") with pytest.raises(sf.program_utils.CircuitError, match="due to incompatible mode ordering."): prog.compile(device=device, compiler="TD2")
def test_tdm_wrong_parameter_second_argument(self): """Test the correct error is raised when the tdm circuit explicit parameters are not within the allowed ranges""" sq_r = 0.5643 c = 2 alpha = [np.pi / 4, 0] * c phi = [0, np.pi / 2] * c theta = [0, 0] + [np.pi / 2, np.pi / 2] prog = tdmprogram.TDMProgram(N=2) with prog.context(alpha, phi, theta) as (p, q): ops.Sgate(sq_r, 0.4) | q[ 1] # Note that the Sgate has a second parameter that is non-zero ops.BSgate(p[0]) | (q[1], q[0]) ops.Rgate(p[1]) | q[1] ops.MeasureHomodyne(p[2]) | q[0] eng = sf.Engine("gaussian") with pytest.raises(sf.program_utils.CircuitError, match="due to incompatible parameter."): prog.compile(device=device, compiler="TD2")
def singleloop_program(r, alpha, phi, theta): """Single delay loop with program. Args: r (float): squeezing parameter alpha (Sequence[float]): beamsplitter angles phi (Sequence[float]): rotation angles theta (Sequence[float]): homodyne measurement angles Returns: (array): homodyne samples from the single loop simulation """ prog = tdmprogram.TDMProgram(N=2) with prog.context(alpha, phi, theta) as (p, q): ops.Sgate(r, 0) | q[1] ops.BSgate(p[0]) | (q[1], q[0]) ops.Rgate(p[1]) | q[1] ops.MeasureHomodyne(p[2]) | q[0] return prog
def test_tdm_wrong_layout(self): """Test the correct error is raised when the tdm circuit gates don't match the device spec""" sq_r = 0.5643 c = 2 alpha = [np.pi / 4, 0] * c phi = [0, np.pi / 2] * c theta = [0, 0] + [np.pi / 2, np.pi / 2] prog = tdmprogram.TDMProgram(N=2) with prog.context(alpha, phi, theta) as (p, q): ops.Dgate(sq_r) | q[1] # Here one should have an Sgate ops.BSgate(p[0]) | (q[1], q[0]) ops.Rgate(p[1]) | q[1] ops.MeasureHomodyne(p[2]) | q[0] eng = sf.Engine("gaussian") with pytest.raises( sf.program_utils.CircuitError, match="The gates or the order of gates used in the Program", ): prog.compile(device=device, compiler="TD2")
def test_spatial_modes_number_of_measurements_match(self): """Checks number of spatial modes matches number of measurements""" sq_r = 1.0 shots = 1 alpha = [0] * 4 phi = [0] * 4 theta = [0] * 4 with pytest.raises( ValueError, match= "Number of measurement operators must match number of spatial modes." ): prog = tdmprogram.TDMProgram(N=[3, 3]) with prog.context(alpha, phi, theta) as (p, q): ops.Sgate(sq_r, 0) | q[2] ops.BSgate(p[0]) | (q[1], q[2]) ops.Rgate(p[1]) | q[2] ops.MeasureHomodyne(p[2]) | q[0] eng = sf.Engine("gaussian") result = eng.run(prog, shots=shots)
def singleloop(r, alpha, phi, theta, shots, shift="default"): """Single-loop program. Args: r (float): squeezing parameter alpha (Sequence[float]): beamsplitter angles phi (Sequence[float]): rotation angles theta (Sequence[float]): homodyne measurement angles shots (int): number of shots shift (string): type of shift used in the program Returns: (list): homodyne samples from the single loop simulation """ prog = tdmprogram.TDMProgram(N=2) with prog.context(alpha, phi, theta, shift=shift) as (p, q): ops.Sgate(r, 0) | q[1] ops.BSgate(p[0]) | (q[0], q[1]) ops.Rgate(p[1]) | q[1] ops.MeasureHomodyne(p[2]) | q[0] eng = sf.Engine("gaussian") result = eng.run(prog, shots=shots) return result.samples
def singleloop(r, alpha, phi, theta, copies, shift="default", hbar=2): """Single delay loop with program. Args: r (float): squeezing parameter alpha (Sequence[float]): beamsplitter angles phi (Sequence[float]): rotation angles theta (Sequence[float]): homodyne measurement angles hbar (float): value in appearing in the commutation relation Returns: (list): homodyne samples from the single loop simulation """ prog = tdmprogram.TDMProgram(N=2) with prog.context(alpha, phi, theta, copies=copies, shift=shift) as (p, q): ops.Sgate(r, 0) | q[1] ops.BSgate(p[0]) | (q[0], q[1]) ops.Rgate(p[1]) | q[1] ops.MeasureHomodyne(p[2]) | q[0] eng = sf.Engine("gaussian") result = eng.run(prog, hbar=hbar) return result.samples[0]
def test_two_dimensional_cluster_tokyo(): """ Two-dimensional temporal-mode cluster state as demonstrated by Universtiy of Tokyo. See: https://arxiv.org/pdf/1903.03918.pdf """ # temporal delay in timebins for each spatial mode delayA = 0 delayB = 1 delayC = 5 delayD = 0 # concurrent modes in each spatial mode concurrA = 1 + delayA concurrB = 1 + delayB concurrC = 1 + delayC concurrD = 1 + delayD N = [concurrA, concurrB, concurrC, concurrD] sq_r = 5 # first half of cluster state measured in X, second half in P n = 400 # number of timebins theta_A = [0] * int(n / 2) + [np.pi / 2] * int( n / 2) # measurement angles for detector A theta_B = theta_A # measurement angles for detector B theta_C = theta_A theta_D = theta_A shots = 10 # 2D cluster prog = tdmprogram.TDMProgram(N) with prog.context(theta_A, theta_B, theta_C, theta_D, shift="default") as (p, q): ops.Sgate(sq_r, 0) | q[0] ops.Sgate(sq_r, 0) | q[2] ops.Sgate(sq_r, 0) | q[8] ops.Sgate(sq_r, 0) | q[9] ops.Rgate(np.pi / 2) | q[0] ops.Rgate(np.pi / 2) | q[8] ops.BSgate(np.pi / 4) | (q[0], q[2]) ops.BSgate(np.pi / 4) | (q[8], q[9]) ops.BSgate(np.pi / 4) | (q[2], q[8]) ops.BSgate(np.pi / 4) | (q[0], q[1]) ops.BSgate(np.pi / 4) | (q[3], q[9]) ops.MeasureHomodyne(p[0]) | q[0] ops.MeasureHomodyne(p[1]) | q[1] ops.MeasureHomodyne(p[2]) | q[3] ops.MeasureHomodyne(p[3]) | q[9] eng = sf.Engine("gaussian") result = eng.run(prog, shots=shots) reshaped_samples = result.samples for sh in range(shots): X_A = reshaped_samples[sh][0][:n // 2] # X samples from detector A P_A = reshaped_samples[sh][0][n // 2:] # P samples from detector A X_B = reshaped_samples[sh][1][:n // 2] # X samples from detector B P_B = reshaped_samples[sh][1][n // 2:] # P samples from detector B X_C = reshaped_samples[sh][2][:n // 2] # X samples from detector C P_C = reshaped_samples[sh][2][n // 2:] # P samples from detector C X_D = reshaped_samples[sh][3][:n // 2] # X samples from detector D P_D = reshaped_samples[sh][3][n // 2:] # P samples from detector D N = delayC # nullifiers defined in https://arxiv.org/pdf/1903.03918.pdf, Fig. S5 ntot = len(X_A) - N - 1 nX1 = np.array([ X_A[k] + X_B[k] - np.sqrt(1 / 2) * (-X_A[k + 1] + X_B[k + 1] + X_C[k + N] + X_D[k + N]) for k in range(ntot) ]) nX2 = np.array([ X_C[k] - X_D[k] - np.sqrt(1 / 2) * (-X_A[k + 1] + X_B[k + 1] - X_C[k + N] - X_D[k + N]) for k in range(ntot) ]) nP1 = np.array([ P_A[k] + P_B[k] + np.sqrt(1 / 2) * (-P_A[k + 1] + P_B[k + 1] + P_C[k + N] + P_D[k + N]) for k in range(ntot) ]) nP2 = np.array([ P_C[k] - P_D[k] + np.sqrt(1 / 2) * (-P_A[k + 1] + P_B[k + 1] - P_C[k + N] - P_D[k + N]) for k in range(ntot) ]) nX1var = np.var(nX1) nX2var = np.var(nX2) nP1var = np.var(nP1) nP2var = np.var(nP2) assert np.allclose(nX1var, 2 * sf.hbar * np.exp(-2 * sq_r), rtol=5 / np.sqrt(ntot)) assert np.allclose(nX2var, 2 * sf.hbar * np.exp(-2 * sq_r), rtol=5 / np.sqrt(ntot)) assert np.allclose(nP1var, 2 * sf.hbar * np.exp(-2 * sq_r), rtol=5 / np.sqrt(ntot)) assert np.allclose(nP2var, 2 * sf.hbar * np.exp(-2 * sq_r), rtol=5 / np.sqrt(ntot))
def test_str_tdm_method(): """Testing the string method""" prog = tdmprogram.TDMProgram(N=1) assert prog.__str__( ) == "<TDMProgram: concurrent modes=1, time bins=0, spatial modes=0>"