def prepare_gaussian_state(self, r, V, modes): if isinstance(modes, int): modes = [modes] # make sure number of modes matches shape of r and V N = len(modes) if len(r) != 2 * N: raise ValueError("Length of means vector must be twice the number of modes.") if V.shape != (2 * N, 2 * N): raise ValueError( "Shape of covariance matrix must be [2N, 2N], where N is the number of modes." ) # Include these lines to accommodate out of order modes, e.g.[1,0] ordering = np.append(np.argsort(modes), np.argsort(modes) + len(modes)) V = V[ordering, :][:, ordering] r = r[ordering] # convert xp-ordering to symmetric ordering means = np.vstack([r[:N], r[N:]]).reshape(-1, order="F") C = changebasis(N) cov = C @ V @ C.T self.circuit.from_covmat(cov, modes) self.circuit.from_mean(means, modes)
def prepare_gaussian_state(self, r, V, modes): r"""Prepare the given Gaussian state (via the provided vector of means and the covariance matrix) in the specified modes. The requested mode(s) is/are traced out and replaced with the given Gaussian state. Args: r (array): the vector of means in xp ordering. V (array): the covariance matrix in xp ordering. modes (int or Sequence[int]): which mode to prepare the state in If the modes are not sorted, this is take into account when preparing the state. i.e., when a two mode state is prepared in modes=[3,1], then the first mode of state goes into mode 3 and the second mode goes into mode 1 of the simulator. """ if isinstance(modes, int): modes = [modes] # make sure number of modes matches shape of r and V N = len(modes) if len(r) != 2 * N: raise ValueError( "Length of means vector must be twice the number of modes.") if V.shape != (2 * N, 2 * N): raise ValueError( "Shape of covariance matrix must be [2N, 2N], where N is the number of modes." ) # convert xp-ordering to symmetric ordering means = vstack([r[:N], r[N:]]).reshape(-1, order='F') C = changebasis(N) cov = C @ V @ C.T self.circuit.fromscovmat(cov, modes) self.circuit.fromsmean(means, modes)
def test_three_mode_arbitrary(self): """Test that the correct result is returned for an arbitrary quadratic polynomial""" self.logTestName() A = np.array([[ 0.7086495 , -0.39299695, 0.30536448, 0.48822049, 0.64987373, 0.7020327 ], [-0.39299695, 0.0284145 , 0.53202656, 0.20232385, 0.26288656, 0.20772833], [ 0.30536448, 0.53202656, 0.28126466, 0.64192545, -0.36583748, 0.51704656], [ 0.48822049, 0.20232385, 0.64192545, 0.51033017, 0.29129713, 0.77103581], [ 0.64987373, 0.26288656, -0.36583748, 0.29129713, 0.37646972, 0.2383589 ], [ 0.7020327 , 0.20772833, 0.51704656, 0.77103581, 0.2383589 ,-0.96494418]]) d = np.array([ 0.71785224, -0.80064627, 0.08799823, 0.76189805, 0.99665321, -0.60777437]) k = 0.123 self.circuit.reset(pure=self.kwargs['pure']) a_list = [0.044+0.023j, 0.0432+0.123j, -0.12+0.04j] r_list = [0.1065, 0.032, -0.123] phi_list = [0.897, 0.31, 0.432] mu = np.zeros([6]) cov = np.zeros([6, 6]) # squeeze and displace each mode for i, (a_, r_, phi_) in enumerate(zip(a_list, r_list, phi_list)): self.circuit.prepare_displaced_squeezed_state(a_, r_, phi_, i) mu[2*i:2*i+2] = R(self.qphi).T @ np.array([a_.real, a_.imag]) * np.sqrt(2*self.hbar) cov[2*i:2*i+2, 2*i:2*i+2] = R(self.qphi).T @ squeezed_cov(r_, phi_, hbar=self.hbar) @ R(self.qphi) # apply a beamsplitter to the modes self.circuit.beamsplitter(1/np.sqrt(2), 1/np.sqrt(2), 0, 1) self.circuit.beamsplitter(1/np.sqrt(2), 1/np.sqrt(2), 1, 2) state = self.circuit.state() mean, var = state.poly_quad_expectation(A, d, k, phi=self.qphi) # apply a beamsplitter to vector of means and covariance matrices t = 1/np.sqrt(2) BS = np.array([[ t, 0, -t, 0], [ 0, t, 0, -t], [ t, 0, t, 0], [ 0, t, 0, t]]) S1 = block_diag(BS, np.identity(2)) S2 = block_diag(np.identity(2), BS) C = changebasis(3) mu = C.T @ S2 @ S1 @ mu cov = C.T @ S2 @ S1 @ cov @ S1.T @ S2.T @ C modes = list(np.arange(6).reshape(2,-1).T) mean_ex = np.trace(A @ cov) + mu @ A @ mu + mu @ d + k var_ex = 2*np.trace(A @ cov @ A @ cov) + 4*mu.T @ A.T @ cov @ A @ mu + d.T @ cov @ d \ + 2*mu.T @ A.T @ cov @ d + 2*d.T @ cov @ A @ mu \ - np.sum([np.linalg.det(self.hbar*A[:, m][n]) for m in modes for n in modes]) self.assertAlmostEqual(mean, mean_ex, delta=self.tol) self.assertAlmostEqual(var, var_ex, delta=self.tol)
def test_means_changebasis(self): """Test the change of basis function applied to vectors. This function converts from xp to symmetric ordering, and vice versa.""" C = so.changebasis(3) means_xp = [1, 2, 3, 4, 5, 6] means_symmetric = [1, 4, 2, 5, 3, 6] assert np.all(C @ means_xp == means_symmetric) assert np.all(C.T @ means_symmetric == means_xp)
def test_cov_changebasis(self): """Test the change of basis function applied to matrices. This function converts from xp to symmetric ordering, and vice versa.""" C = so.changebasis(2) cov_xp = np.array( [[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11], [12, 13, 14, 15]] ) cov_symmetric = np.array( [[0, 2, 1, 3], [8, 10, 9, 11], [4, 6, 5, 7], [12, 14, 13, 15]] ) assert np.all(C @ cov_xp @ C.T == cov_symmetric) assert np.all(C.T @ cov_symmetric @ C == cov_xp)
def test_rotated_squeezed(self, setup_eng, hbar, tol): """Testing a rotated squeezed state""" eng, prog = setup_eng(3) r = 0.1 phi = 0.2312 v1 = (hbar / 2) * np.diag([np.exp(-r), np.exp(r)]) A = changebasis(3) cov = A.T @ block_diag(*[rot(phi) @ v1 @ rot(phi).T] * 3) @ A with prog.context as q: ops.Gaussian(cov, decomp=False) | q state = eng.run(prog).state assert np.allclose(state.cov(), cov, atol=tol)
def test_covariance_rotated_squeezed(self): self.logTestName() q = self.eng.register r = 0.1 phi = 0.2312 v1 = (self.hbar / 2) * np.diag([np.exp(-r), np.exp(r)]) A = changebasis(3) cov = A.T @ block_diag(*[rot(phi) @ v1 @ rot(phi).T] * 3) @ A with self.eng: Gaussian(cov, decomp=False) | q state = self.eng.run() self.assertAllAlmostEqual(state.cov(), cov, delta=self.tol)
def test_rotated_squeezed(self, setup_eng, hbar, tol): """Testing decomposed rotated squeezed state""" eng, q = setup_eng(3) r = 0.1 phi = 0.2312 v1 = (hbar / 2) * np.diag([np.exp(-r), np.exp(r)]) A = changebasis(3) cov = A.T @ block_diag(*[rot(phi) @ v1 @ rot(phi).T] * 3) @ A with eng: ops.Gaussian(cov) | q state = eng.run() assert np.allclose(state.cov(), cov, atol=tol) assert np.all(len(eng.cmd_applied[0]) == 3)
def test_covariance_rotated_squeezed(self): self.eng.reset() q = self.eng.register r = 0.1 phi = 0.2312 v1 = (self.hbar / 2) * np.diag([np.exp(-r), np.exp(r)]) A = changebasis(3) cov = A.T @ block_diag(*[rot(phi) @ v1 @ rot(phi).T] * 3) @ A with self.eng: CovarianceState(cov) | q state = self.eng.run(backend=self.backend_name, cutoff_dim=self.D) self.assertAllAlmostEqual(state.cov(), cov, delta=self.tol) self.assertAllEqual(len(self.eng.cmd_applied), 3)
def prepare_gaussian_state(self, r, V, modes): if isinstance(modes, int): modes = [modes] # make sure number of modes matches shape of r and V N = len(modes) if len(r) != 2*N: raise ValueError("Length of means vector must be twice the number of modes.") if V.shape != (2*N, 2*N): raise ValueError("Shape of covariance matrix must be [2N, 2N], where N is the number of modes.") # convert xp-ordering to symmetric ordering means = vstack([r[:N], r[N:]]).reshape(-1, order='F') C = changebasis(N) cov = C @ V @ C.T self.circuit.fromscovmat(cov, modes) self.circuit.fromsmean(means, modes)
def test_rotated_squeezed(self, setup_eng, cutoff, hbar, tol): eng, q = setup_eng(3) r = 0.1 phi = 0.2312 in_state = squeezed_state(r, phi, basis="fock", fock_dim=cutoff) v1 = (hbar / 2) * np.diag([np.exp(-2 * r), np.exp(2 * r)]) A = changebasis(3) cov = A.T @ block_diag(*[rot(phi) @ v1 @ rot(phi).T] * 3) @ A with eng: ops.Gaussian(cov) | q state = eng.run() assert len(eng.cmd_applied[0]) == 3 for n in range(3): assert np.allclose(state.fidelity(in_state, n), 1, atol=tol)
def test_covariance_rotated_squeezed(self): self.logTestName() q = self.eng.register r = 0.1 phi = 0.2312 in_state = squeezed_state(r, phi, basis='fock', fock_dim=self.D) v1 = (self.hbar / 2) * np.diag([np.exp(-2 * r), np.exp(2 * r)]) A = changebasis(3) cov = A.T @ block_diag(*[rot(phi) @ v1 @ rot(phi).T] * 3) @ A with self.eng: Gaussian(cov) | q state = self.eng.run(**self.kwargs) self.assertAllEqual(len(self.eng.cmd_applied[0]), 3) for n in range(3): self.assertAllAlmostEqual(state.fidelity(in_state, n), 1, delta=self.tol)
def test_three_mode_arbitrary(self, setup_backend, pure, hbar, tol): """Test that the correct result is returned for an arbitrary quadratic polynomial""" backend = setup_backend(3) # increase the cutoff to 7 for accuracy backend.reset(cutoff_dim=7, pure=pure) # fmt:off A = np.array([[ 0.7086495, -0.39299695, 0.30536448, 0.48822049, 0.64987373, 0.7020327 ], [ -0.39299695, 0.0284145, 0.53202656, 0.20232385, 0.26288656, 0.20772833 ], [ 0.30536448, 0.53202656, 0.28126466, 0.64192545, -0.36583748, 0.51704656 ], [ 0.48822049, 0.20232385, 0.64192545, 0.51033017, 0.29129713, 0.77103581 ], [ 0.64987373, 0.26288656, -0.36583748, 0.29129713, 0.37646972, 0.2383589 ], [ 0.7020327, 0.20772833, 0.51704656, 0.77103581, 0.2383589, -0.96494418 ]]) # fmt:on d = np.array([ 0.71785224, -0.80064627, 0.08799823, 0.76189805, 0.99665321, -0.60777437 ]) k = 0.123 a_list = [0.044 + 0.023j, 0.0432 + 0.123j, -0.12 + 0.04j] r_list = [0.1065, 0.032, -0.123] phi_list = [0.897, 0.31, 0.432] mu = np.zeros([6]) cov = np.zeros([6, 6]) # squeeze and displace each mode for i, (a_, r_, phi_) in enumerate(zip(a_list, r_list, phi_list)): backend.prepare_displaced_squeezed_state(np.abs(a_), np.angle(a_), r_, phi_, i) mu[2 * i:2 * i + 2] = (R(qphi).T @ np.array([a_.real, a_.imag]) * np.sqrt(2 * hbar)) cov[2 * i:2 * i + 2, 2 * i:2 * i + 2] = ( R(qphi).T @ utils.squeezed_cov(r_, phi_, hbar=hbar) @ R(qphi)) # apply a beamsplitter to the modes backend.beamsplitter(np.pi / 4, 0.0, 0, 1) backend.beamsplitter(np.pi / 4, 0.0, 1, 2) state = backend.state() mean, var = state.poly_quad_expectation(A, d, k, phi=qphi) # apply a beamsplitter to vector of means and covariance matrices t = 1 / np.sqrt(2) BS = np.array([[t, 0, -t, 0], [0, t, 0, -t], [t, 0, t, 0], [0, t, 0, t]]) S1 = block_diag(BS, np.identity(2)) S2 = block_diag(np.identity(2), BS) C = changebasis(3) mu = C.T @ S2 @ S1 @ mu cov = C.T @ S2 @ S1 @ cov @ S1.T @ S2.T @ C modes = list(np.arange(6).reshape(2, -1).T) mean_ex = np.trace(A @ cov) + mu @ A @ mu + mu @ d + k var_ex = (2 * np.trace(A @ cov @ A @ cov) + 4 * mu.T @ A.T @ cov @ A @ mu + d.T @ cov @ d + 2 * mu.T @ A.T @ cov @ d + 2 * d.T @ cov @ A @ mu - np.sum([ np.linalg.det(hbar * A[:, m][n]) for m in modes for n in modes ])) assert np.allclose(mean, mean_ex, atol=tol, rtol=0) assert np.allclose(var, var_ex, atol=tol, rtol=0)