def test_all(self, hbar, tol): """Test requesting all wires returns the full state""" mu, cov = symplectic.vacuum_state(4, hbar=hbar) res = symplectic.reduced_state(mu, cov, [0, 1, 2, 3]) expected = np.zeros([8]), np.identity(8) * hbar / 2 assert np.allclose(res[0], expected[0], atol=tol, rtol=0) assert np.allclose(res[1], expected[1], atol=tol, rtol=0)
def test_integer(self, hbar, tol): """Test requesting via an integer""" mu, cov = symplectic.vacuum_state(4, hbar=hbar) res = symplectic.reduced_state(mu, cov, 0) expected = np.zeros([2]), np.identity(2) * hbar / 2 assert np.allclose(res[0], expected[0], atol=tol, rtol=0) assert np.allclose(res[1], expected[1], atol=tol, rtol=0)
def test_vacuum_state(self, hbar, tol): """Test the vacuum state is correct.""" modes = 3 means, cov = symplectic.vacuum_state(modes, hbar=hbar) assert np.allclose(means, np.zeros([2 * modes]), atol=tol, rtol=0) assert np.allclose(cov, np.identity(2 * modes) * hbar / 2, atol=tol, rtol=0)
def test_inverse_ops_cancel(self, hbar, tol): """Test that applying squeezing and interferometers to a four mode circuit, followed by applying the inverse operations, return the state to the vacuum""" # the symplectic matrix O = np.block([[np.zeros([4, 4]), np.identity(4)], [-np.identity(4), np.zeros([4, 4])]]) # begin in the vacuum state mu_init, cov_init = symplectic.vacuum_state(4, hbar=hbar) # add displacement alpha = np.random.random(size=[4]) + np.random.random(size=[4]) * 1j D = np.concatenate([alpha.real, alpha.imag]) mu = mu_init + D cov = cov_init.copy() # random squeezing r = np.random.random() phi = np.random.random() S = symplectic.expand(symplectic.two_mode_squeezing(r, phi), modes=[0, 1], N=4) # check symplectic assert np.allclose(S @ O @ S.T, O, atol=tol, rtol=0) # random interferometer # fmt:off u = np.array([[ -0.06658906 - 0.36413058j, 0.07229868 + 0.65935896j, 0.59094625 - 0.17369183j, -0.18254686 - 0.10140904j ], [ 0.53854866 + 0.36529723j, 0.61152793 + 0.15022026j, 0.05073631 + 0.32624882j, -0.17482023 - 0.20103772j ], [ 0.34818923 + 0.51864844j, -0.24334624 + 0.0233729j, 0.3625974 - 0.4034224j, 0.10989667 + 0.49366039j ], [ 0.16548085 + 0.14792642j, -0.3012549 - 0.11387682j, -0.12731847 - 0.44851389j, -0.55816075 - 0.5639976j ]]) # fmt on U = symplectic.interferometer(u) # check unitary assert np.allclose(u @ u.conj().T, np.identity(4), atol=tol, rtol=0) # check symplectic assert np.allclose(U @ O @ U.T, O, atol=tol, rtol=0) # apply squeezing and interferometer cov = U @ S @ cov @ S.T @ U.T mu = U @ S @ mu # check we are no longer in the vacuum state assert not np.allclose(mu, mu_init, atol=tol, rtol=0) assert not np.allclose(cov, cov_init, atol=tol, rtol=0) # return the inverse operations Sinv = symplectic.expand(symplectic.two_mode_squeezing(-r, phi), modes=[0, 1], N=4) Uinv = symplectic.interferometer(u.conj().T) # check inverses assert np.allclose(Uinv, np.linalg.inv(U), atol=tol, rtol=0) assert np.allclose(Sinv, np.linalg.inv(S), atol=tol, rtol=0) # apply the inverse operations cov = Sinv @ Uinv @ cov @ Uinv.T @ Sinv.T mu = Sinv @ Uinv @ mu # inverse displacement mu -= D # check that we return to the vacuum state assert np.allclose(mu, mu_init, atol=tol, rtol=0) assert np.allclose(cov, cov_init, atol=tol, rtol=0)