def test_pnd_thermal(tol, n, N, hbar): """Test the photon number distribution for thermal states""" cov = np.eye(2 * N) * hbar / 2 * (2 * n + 1) mu = np.zeros(2 * N) pnd_cov = photon_number_covmat(mu, cov, hbar=hbar) assert np.allclose(pnd_cov, np.diag([n ** 2 + n] * N), atol=tol, rtol=0)
def test_pnd_coherent_state(tol, list_func, N, hbar): r"""Test the covariance matrix :math:`\frac{\hbar}{2} \mathbb{I}`.""" cov = np.eye(2 * N) * hbar / 2 mu = list_func(2 * N) pnd_cov = photon_number_covmat(mu, cov, hbar=hbar) alpha = (mu[:N] ** 2 + mu[N:] ** 2) / (2 * hbar) assert np.allclose(pnd_cov, np.diag(alpha), atol=tol, rtol=0)
def test_pnd_two_mode_squeeze_vacuum(tol, r, phi, hbar): """Test the photon number distribution for the two-mode squeezed vacuum""" S = two_mode_squeezing(r, phi) mu = np.zeros(4) cov = hbar / 2 * (S @ S.T) pnd_cov = photon_number_covmat(mu, cov, hbar=hbar) n = np.sinh(r) ** 2 assert np.allclose(pnd_cov, np.full((2, 2), n ** 2 + n), atol=tol, rtol=0)
def get_photon_number_moments(gate_args, device, phi_loop=None, delays=[1, 6, 36]): """Computes first and second moment of the photon number distribution obtained from a single Args: gate_args (_type_): dictionary with the collected arguments for squeezing gate, phase gates and beamsplitter gates device (sf.Device): the Borealis device phi_loop (list, optional): list containing the three loop offsets. Defaults to None. delays (list, optional): the delay applied by each loop in time bins. Returns: tuple: two np.ndarrays with the mean photon numbers and photon-number covariance matrix, respectively """ args_list = to_args_list(gate_args, device) n, N = get_mode_indices(delays) prog = sf.TDMProgram(N) with prog.context(*args_list) as (p, q): ops.Sgate(p[0]) | q[n[0]] for i in range(len(delays)): ops.Rgate(p[2 * i + 1]) | q[n[i]] ops.BSgate(p[2 * i + 2], np.pi / 2) | (q[n[i]], q[n[i + 1]]) if phi_loop is not None: ops.Rgate(phi_loop[i]) | q[n[i]] prog.space_unroll() eng = sf.Engine("gaussian") results = eng.run(prog) assert isinstance(results.state, BaseGaussianState) # quadrature mean vector and covariance matrix mu = results.state.means() cov_q = results.state.cov() # photon-number mean vector and covariance matrix mean_n = photon_number_mean_vector(mu, cov_q) cov_n = photon_number_covmat(mu, cov_q) return mean_n, cov_n
def test_pnd_squeeze_displace(tol, r, phi, alpha, hbar): """Test the photon number distribution for the squeezed displaced state Eq. (17) in 'Benchmarking of Gaussian boson sampling using two-point correlators', Phillips et al. (https://ris.utwente.nl/ws/files/122721825/PhysRevA.99.023836.pdf). """ S = squeezing(r, phi) mu = [np.sqrt(2 * hbar) * np.real(alpha), np.sqrt(2 * hbar) * np.imag(alpha)] cov = hbar / 2 * (S @ S.T) pnd_cov = photon_number_covmat(mu, cov, hbar=hbar) pnd_cov_analytic = np.sinh(r) ** 2 * np.cosh(r) ** 2 + np.sinh(r) ** 4 \ + np.sinh(r) ** 2 + np.abs(alpha) ** 2 * (1 + 2 * np.sinh(r) ** 2) \ - 2 * np.real(alpha ** 2 * np.exp(-1j * phi) * np.sinh(r) * np.cosh(r)) assert np.isclose(float(pnd_cov), pnd_cov_analytic, atol=tol, rtol=0)
Sgate(p[0]) | q[n[0]] LossChannel(eta_glob) | q[n[0]] for i in range(len(delays)): Rgate(p[2 * i + 1]) | q[n[i]] BSgate(p[2 * i + 2], np.pi / 2) | (q[n[i + 1]], q[n[i]]) LossChannel(etas_loop[i]) | q[n[i]] LossChannel(p[7]) | q[0] MeasureFock() | q[0] prog_sim.space_unroll() # create Gaussian engine and submit program to it eng_sim = sf.Engine(backend="gaussian") results_sim = eng_sim.run(prog_sim, shots=None, crop=True) # obtain quadrature covariance matrix cov = results_sim.state.cov() # obtain first and second moment mu = np.zeros(len(cov)) mean_n_sim = photon_number_mean_vector(mu, cov) cov_n_sim = photon_number_covmat(mu, cov) # plot first and second moment of the simulated data plot_photon_number_moments(mean_n_sim, cov_n_sim) # plot statistical comparison between data and simulation plot_photon_number_moment_comparison(mean_n, mean_n_sim, cov_n, cov_n_sim) # show all plots plt.show()