def test_merge(self, hbar, tol): """Test that two covariances matrices overwrite each other on merge""" n = 3 V1 = random_covariance(n, pure=False, hbar=hbar) V2 = random_covariance(n, pure=True, hbar=hbar) cov1 = ops.Gaussian(V1, hbar=hbar) cov2 = ops.Gaussian(V2, hbar=hbar) # applying a second covariance matrix replaces the first assert cov1.merge(cov2) == cov2 # the same is true of state preparations assert ops.Squeezed(2).merge(cov2) == cov2
def test_multimode_gaussian_random_state(self, setup_backend, batch_size, pure, tol, hbar): """Test multimode Gaussian state preparation on a random state""" N = 4 backend = setup_backend(N) means = 2 * np.random.random(size=[2 * N]) - 1 cov = random_covariance(N, pure=pure) backend.reset(pure=pure) # circuit is initially in a random state backend.prepare_gaussian_state(means, cov, modes=range(N)) # test Gaussian state is correct state = backend.state() assert np.allclose(state.means(), np.array([means[from_xp(N)]]) * np.sqrt(hbar / 2), atol=tol, rtol=0) assert np.allclose(state.covs(), np.array([cov[from_xp(N), :][:, from_xp(N)]]) * hbar / 2, atol=tol, rtol=0)
def test_singlemode_gaussian_state(self, setup_backend, batch_size, pure, tol): """Test single mode Gaussian state preparation""" N = 4 backend = setup_backend(N) means = 2 * np.random.random(size=[2]) - 1 cov = random_covariance(1, pure=pure) a = 0.2 + 0.4j r = 1 phi = 0 # circuit is initially in displaced squeezed state for i in range(N): backend.prepare_displaced_squeezed_state(a, r, phi, mode=i) # prepare Gaussian state in mode 1 backend.prepare_gaussian_state(means, cov, modes=1) # test Gaussian state is correct state = backend.state([1]) assert np.allclose(state.means(), means, atol=tol, rtol=0) assert np.allclose(state.cov(), cov, atol=tol, rtol=0) # test that displaced squeezed states are unchanged ex_means, ex_V = displaced_squeezed_state(a, r, phi, basis="gaussian") for i in [0, 2, 3]: state = backend.state([i]) assert np.allclose(state.means(), ex_means, atol=tol, rtol=0) assert np.allclose(state.cov(), ex_V, atol=tol, rtol=0)
def test_decomposition(self, hbar, tol): """Test that an arbitrary decomposition provides the right covariance matrix""" n = 3 prog = sf.Program(n) cov = random_covariance(n) G = ops.Gaussian(cov) cmds = G.decompose(prog.register) S = np.identity(2 * n) cov_init = np.identity(2 * n) * hbar / 2 # calculating the resulting decomposed symplectic for cmd in cmds: # all operations should be BSgates, Rgates, or Sgates assert isinstance(cmd.op, (ops.Vacuum, ops.Thermal, ops.GaussianTransform)) # build up the symplectic transform modes = [i.ind for i in cmd.reg] if isinstance(cmd.op, ops.Thermal): cov_init[cmd.reg[0].ind, cmd.reg[0].ind] = ((2 * cmd.op.p[0].x + 1) * hbar / 2) cov_init[cmd.reg[0].ind + n, cmd.reg[0].ind + n] = ((2 * cmd.op.p[0].x + 1) * hbar / 2) if isinstance(cmd.op, ops.GaussianTransform): S = cmd.op.p[0].x @ S # the resulting covariance state cov_res = S @ cov_init @ S.T assert np.allclose(cov, cov_res, atol=tol, rtol=0)
def test_random_covariance_square(self, modes, hbar, pure_state, block_diag): """Test that a random covariance matrix is the right shape""" V = utils.random_covariance(modes, hbar=hbar, pure=pure_state, block_diag=block_diag) assert np.all(V.shape == np.array([2 * modes, 2 * modes]))
def test_random_covariance_symmetric(self, modes, hbar, pure_state, tol, block_diag): """Test that a random covariance matrix is symmetric""" V = utils.random_covariance(modes, hbar=hbar, pure=pure_state, block_diag=block_diag) assert np.allclose(V.T, V, atol=tol, rtol=0)
def test_random_covariance_mixed(self, modes, hbar, tol, block_diag): """Test that a mixed random covariance matrix has correct purity""" V = utils.random_covariance(modes, hbar=hbar, pure=False, block_diag=block_diag) det = np.linalg.det(V) - (hbar / 2)**(2 * modes) assert not np.allclose(det, 0, atol=tol, rtol=0)
def test_merge(self, hbar, tol): """Test that merging two Preparations only keeps the latter one.""" n = 3 V1 = random_covariance(n, pure=False, hbar=hbar) V2 = random_covariance(n, pure=True, hbar=hbar) r1 = np.random.randn(2 * n) r2 = np.random.randn(2 * n) G1 = ops.Gaussian(V1, r1) G2 = ops.Gaussian(V2, r2) # applying a second state preparation replaces the first assert G1.merge(G2) is G2 # the same is true of all state preparations S = ops.Squeezed(2) assert S.merge(G2) is G2 assert G2.merge(S) is S
def test_apply_decomp(self, hbar): """Test that the apply method, when decomp = True, raises a NotImplemented error.""" prog = sf.Program(3, hbar=hbar) cov = random_covariance(3, hbar=hbar) with eng: G = ops.Gaussian(cov, decomp=True) with pytest.raises(NotImplementedError): G._apply(q, None)
def test_random_covariance_valid(self, modes, hbar, pure_state, tol, block_diag): """Test that a random covariance matrix satisfies the uncertainty principle V+i hbar O/2 >=0""" V = utils.random_covariance(modes, hbar=hbar, pure=pure_state, block_diag=block_diag) idm = np.identity(modes) omega = np.concatenate( (np.concatenate((0 * idm, idm), axis=1), np.concatenate((-idm, 0 * idm), axis=1)), axis=0, ) eigs = np.linalg.eigvalsh(V + 1j * (hbar / 2) * omega) eigs[np.abs(eigs) < tol] = 0 assert np.all(eigs >= 0)
def test_apply_decomp(self, hbar): """Test that the apply method, when decomp = False, calls the Backend directly.""" prog = sf.Program(3) cov = random_covariance(3, hbar=hbar) class DummyBackend: """Dummy backend class""" def prepare_gaussian_state(*args): """Raises a syntax error when called""" raise SyntaxError G = ops.Gaussian(cov, decomp=False) with pytest.raises(SyntaxError): G._apply(prog.register, DummyBackend())
def test_setting_hbar(self, hbar): """Test that an exception is raised if hbar not provided""" prog = sf.Program(3, hbar=hbar) cov = random_covariance(3, hbar=hbar) with pytest.raises(ValueError, match="specify the hbar keyword argument"): ops.Gaussian(cov) # hbar can be passed as a keyword arg G = ops.Gaussian(cov, hbar=hbar) assert G.hbar == hbar # or determined via the engine context with eng: G = ops.Gaussian(cov) assert G.hbar == hbar
def test_random_covariance_pure(self, modes, hbar, tol): """Test that a pure random covariance matrix has correct purity""" V = utils.random_covariance(modes, hbar=hbar, pure=True) det = np.linalg.det(V) - (hbar / 2)**(2 * modes) assert np.allclose(det, 0, atol=tol, rtol=0)
def V_pure(hbar): return random_covariance(3, hbar=hbar, pure=True)
def V_mixed(hbar): return random_covariance(3, hbar=hbar, pure=False)
def test_multimode_gaussian_random_state_with_replacement( self, setup_backend, batch_size, pure, tol, hbar): """Test multimode Gaussian state preparation on a random state with replacement""" N = 4 backend = setup_backend(N) means = 2 * np.random.random(size=[2 * N]) - 1 cov = random_covariance(N, pure=pure) backend.reset(pure=pure) # circuit is initially in a random state backend.prepare_gaussian_state(means, cov, modes=range(N)) # test Gaussian state is correct state = backend.state() # prepare Gaussian state in mode 2 and 1 means2 = 2 * np.random.random(size=[4]) - 1 cov2 = random_covariance(2, pure=pure) backend.prepare_gaussian_state(means2, cov2, modes=[2, 1]) # test resulting Gaussian state is correct state = backend.state() # in the new means vector, the modes 0 and 3 remain unchanged # Modes 1 and 2, however, now have values given from elements # means2[1] and means2[0]. ex_means = np.array([ means[0], means2[1], means2[0], means[3], # position means[4], means2[3], means2[2], means[7], ]) # momentum ex_cov = np.zeros([8, 8]) # in the new covariance matrix, modes 0 and 3 remain unchanged idx = np.array([0, 3, 4, 7]) rows = idx.reshape(-1, 1) cols = idx.reshape(1, -1) ex_cov[rows, cols] = cov[rows, cols] # in the new covariance matrix, modes 1 and 2 have values given by # rows 1 and 0 respectively from cov2 idx = np.array([1, 2, 5, 6]) rows = idx.reshape(-1, 1) cols = idx.reshape(1, -1) idx = np.array([1, 0, 3, 2]) rows2 = idx.reshape(-1, 1) cols2 = idx.reshape(1, -1) ex_cov[rows, cols] = cov2[rows2, cols2] assert np.allclose(state.means(), np.array([ex_means[from_xp(4)]]) * np.sqrt(hbar / 2), atol=tol, rtol=0) assert np.allclose( state.covs(), np.array([ex_cov[from_xp(4), :][:, from_xp(4)]]) * hbar / 2, atol=tol, rtol=0, )
def test_incorrect_means_length(self, hbar): """Test that an exception is raised len(means)!=len(cov)""" cov = random_covariance(3, hbar=hbar) with pytest.raises(ValueError, match="must have the same length"): ops.Gaussian(cov, r=np.array([0]))