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 mean_photons_by_mode(self, params: np.ndarray) -> np.ndarray: r"""Calculate the mean number of photons in each mode when using the trainable parameters :math:`\theta`. **Example usage:** >>> vgbs.mean_photons_by_mode(params) array([1.87217857, 1.8217392 , 1.90226515, 1.91225543]) Args: params (array): the trainable parameters :math:`\theta` Returns: array: a vector giving the mean number of photons in each mode """ disp = np.zeros(2 * self.n_modes) cov = A_to_cov(self.A(params)) return photon_number_mean_vector(disp, cov, hbar=sf.hbar)
def _jacobian_all_wires(self, prob): """Calculates the jacobian of the probability distribution with respect to all wires. This function uses Eq. (28) of `this <https://arxiv.org/pdf/2004.04770.pdf>`__ paper. Args: prob (array[float]): the probability distribution as a flat array Returns: array[float]: the jacobian """ n = len(self._WAW) disp = np.zeros(2 * n) cov = self.calculate_covariance(self._WAW, hbar=self.hbar) mean_photons_by_mode = photon_number_mean_vector(disp, cov, hbar=self.hbar) basis_states = np.array(list(np.ndindex(*[self.cutoff] * self.num_wires))) jac = (basis_states - mean_photons_by_mode) * np.expand_dims(prob, 1) / self._params return jac
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()