def test_merge(self, hbar, tol): """Test that two symplectics merge: S = S2 @ S1""" n = 3 S1 = random_symplectic(n) S2 = random_symplectic(n) G1 = ops.GaussianTransform(S1) G1inv = ops.GaussianTransform(np.linalg.inv(S1)) G2 = ops.GaussianTransform(S2) # a symplectic merged with its inverse is identity assert G1.merge(G1inv) is None # two merged symplectics are the same as their product assert np.allclose(G1.merge(G2).p[0].x, S2 @ S1, atol=tol, rtol=0)
def test_decomposition_passive(self, tol): """Test that a passive symplectic is correctly decomposed into an interferometer""" n = 3 S = random_symplectic(n, passive=True) X1 = S[:n, :n] P1 = S[n:, :n] U1 = X1 + 1j * P1 prog = sf.Program(n) G = ops.GaussianTransform(S) cmds = G.decompose(prog.register) S = np.identity(2 * n) # command queue should have 1 interferometer assert len(cmds) == 1 # calculating the resulting decomposed symplectic for cmd in cmds: # all operations should be Interferometers assert isinstance(cmd.op, ops.Interferometer) # build up the symplectic transform #modes = [i.ind for i in cmd.reg] if isinstance(cmd.op, ops.Interferometer): U1 = cmd.op.p[0] S_U = np.vstack( [np.hstack([U1.real, -U1.imag]), np.hstack([U1.imag, U1.real])] ) S = S_U @ S # the resulting covariance state cov = S @ S.T assert np.allclose(cov, S @ S.T, atol=tol, rtol=0)
def test_random_symplectic_active_not_orthogonal(self, modes, hbar, tol, block_diag): """Test that an active random symplectic matrix is not orthogonal""" S = utils.random_symplectic(modes, passive=False, block_diag=block_diag) assert not np.allclose( S @ S.T, np.identity(2 * modes), atol=tol, rtol=0)
def test_active(self, tol): """Test that an active decomposition is correctly flagged as requiring two interferometers and squeezing""" S1 = random_symplectic(3, passive=False) G = ops.GaussianTransform(S1) assert G.active assert hasattr(G, "U1") assert hasattr(G, "Sq") assert hasattr(G, "U2")
def test_random_symplectic_symplectic(self, modes, hbar, passive, tol, block_diag): """Test that a random symplectic matrix is symplectic""" S = utils.random_symplectic(modes, passive=passive, 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, ) assert np.allclose(S @ omega @ S.T, omega, atol=tol, rtol=0)
def test_decomposition_active(self, hbar, tol): """Test that an active symplectic is correctly decomposed into two interferometers and squeezing""" n = 3 S = random_symplectic(n, passive=False) O1, Sq, O2 = dec.bloch_messiah(S) X1 = O1[:n, :n] P1 = O1[n:, :n] X2 = O2[:n, :n] P2 = O2[n:, :n] U1 = X1 + 1j * P1 U2 = X2 + 1j * P2 prog = sf.Program(n, hbar=hbar) with eng: G = ops.GaussianTransform(S) cmds = G.decompose(q) assert np.all(U1 == G.U1) assert np.all(U2 == G.U2) assert np.all(np.diag(Sq)[:n] == G.Sq) S = np.identity(2 * n) # command queue should have 2 interferometers, 3 squeezers assert len(cmds) == 5 # calculating the resulting decomposed symplectic for cmd in cmds: # all operations should be BSgates, Rgates, or Sgates assert isinstance(cmd.op, (ops.Interferometer, ops.Sgate)) # build up the symplectic transform modes = [i.ind for i in cmd.reg] if isinstance(cmd.op, ops.Sgate): S = _squeezing(cmd.op.p[0].x, cmd.op.p[1].x, modes, n) @ S if isinstance(cmd.op, ops.Interferometer): U1 = cmd.op.p[0].x S_U = np.vstack([ np.hstack([U1.real, -U1.imag]), np.hstack([U1.imag, U1.real]) ]) S = S_U @ S # the resulting covariance state cov = S @ S.T assert np.allclose(cov, S @ S.T * hbar / 2, atol=tol, rtol=0)
def test_symplectic_composition(depth, width): """Tests that symplectic operations are composed correctly""" eng = sf.LocalEngine(backend="gaussian") eng1 = sf.LocalEngine(backend="gaussian") circuit = sf.Program(width) Snet = np.identity(2 * width) with circuit.context as q: for _ in range(depth): S = random_symplectic(width, scale=0.2) Snet = S @ Snet ops.GaussianTransform(S) | q compiled_circuit = circuit.compile(compiler="gaussian_unitary") assert np.allclose(compiled_circuit.circuit[0].op.p[0], Snet)
def test_active_on_vacuum(self, hbar, tol): """Test that an active symplectic applied to a vacuum is correctly decomposed into just squeezing and one interferometer""" n = 3 S = random_symplectic(n, passive=False) O1, Sq, O2 = dec.bloch_messiah(S) X1 = O1[:n, :n] P1 = O1[n:, :n] X2 = O2[:n, :n] P2 = O2[n:, :n] U1 = X1 + 1j * P1 U2 = X2 + 1j * P2 prog = sf.Program(n) G = ops.GaussianTransform(S, vacuum=True) cmds = G.decompose(prog.register) S = np.identity(2 * n) # command queue should have 3 Sgates, 1 interferometer assert len(cmds) == 4 # calculating the resulting decomposed symplectic for cmd in cmds: # all operations should be Interferometers or Sgates assert isinstance(cmd.op, (ops.Interferometer, ops.Sgate)) # build up the symplectic transform modes = [i.ind for i in cmd.reg] if isinstance(cmd.op, ops.Sgate): S = _squeezing(cmd.op.p[0].x, cmd.op.p[1].x, modes, n) @ S if isinstance(cmd.op, ops.Interferometer): U1 = cmd.op.p[0].x S_U = np.vstack([ np.hstack([U1.real, -U1.imag]), np.hstack([U1.imag, U1.real]) ]) S = S_U @ S # the resulting covariance state cov = S @ S.T assert np.allclose(cov, S @ S.T, atol=tol, rtol=0)
def test_setting_hbar(self, hbar): """Test that an exception is raised if hbar not provided""" prog = sf.Program(3, hbar=hbar) S1 = random_symplectic(3, passive=False) with pytest.raises(ValueError, match="specify the hbar keyword argument"): ops.GaussianTransform(S1) # hbar can be passed as a keyword arg G = ops.GaussianTransform(S1, hbar=hbar) assert G.hbar == hbar # or determined via the engine context with eng: G = ops.GaussianTransform(S1) assert G.hbar == hbar
def test_random_symplectic_square(self, modes, hbar, passive, block_diag): """Test that a random symplectic matrix on is the right shape""" S = utils.random_symplectic(modes, passive=passive, block_diag=block_diag) assert np.all(S.shape == np.array([2 * modes, 2 * modes]))
random_covariance, squeezed_state, ) from strawberryfields import ops from strawberryfields.backends.shared_ops import ( haar_measure, changebasis, rotation_matrix as rot, ) # make the test file deterministic np.random.seed(42) u1 = random_interferometer(3) u2 = random_interferometer(3) S = random_symplectic(3) @pytest.fixture def V_mixed(hbar): return random_covariance(3, hbar=hbar, pure=False) @pytest.fixture def V_pure(hbar): return random_covariance(3, hbar=hbar, pure=True) @pytest.fixture def r_means(hbar): return np.random.randn(6) * np.sqrt(hbar / 2)
def test_random_symplectic_passive_orthogonal(self, modes, hbar, tol): """Test that a passive random symplectic matrix is orthogonal""" S = utils.random_symplectic(modes, passive=True) assert np.allclose(S @ S.T, np.identity(2 * modes), atol=tol, rtol=0)