def _create_transform(n, passive=True): """wrapped function""" O = omega(n) # interferometer 1 U1 = haar_measure(n) S1 = np.vstack([ np.hstack([U1.real, -U1.imag]), np.hstack([U1.imag, U1.real]) ]) Sq = np.identity(2 * n) if not passive: # squeezing r = np.log(0.2 * np.arange(n) + 2) Sq = block_diag(np.diag(np.exp(-r)), np.diag(np.exp(r))) # interferometer 2 U2 = haar_measure(n) S2 = np.vstack([ np.hstack([U2.real, -U2.imag]), np.hstack([U2.imag, U2.real]) ]) # final symplectic S_final = S2 @ Sq @ S1 # check valid symplectic transform assert np.allclose(S_final.T @ O @ S_final, O) return S_final
def _create_cov(nbar): """wrapped function""" n = len(nbar) O = omega(n) # initial vacuum state cov = np.diag(2 * np.tile(nbar, 2) + 1) * hbar / 2 # interferometer 1 U1 = haar_measure(n) S1 = np.vstack([ np.hstack([U1.real, -U1.imag]), np.hstack([U1.imag, U1.real]) ]) # squeezing r = np.log(0.2 * np.arange(n) + 2) Sq = block_diag(np.diag(np.exp(-r)), np.diag(np.exp(r))) # interferometer 2 U2 = haar_measure(n) S2 = np.vstack([ np.hstack([U2.real, -U2.imag]), np.hstack([U2.imag, U2.real]) ]) # final symplectic S_final = S2 @ Sq @ S1 # final covariance matrix cov_final = S_final @ cov @ S_final.T # check valid symplectic transform assert np.allclose(S_final.T @ O @ S_final, O) # check valid state eigs = np.linalg.eigvalsh(cov_final + 1j * (hbar / 2) * O) eigs[np.abs(eigs) < tol] = 0 assert np.all(eigs >= 0) if np.allclose(nbar, 0): # check pure assert np.allclose(np.linalg.det(cov_final), (hbar / 2)**(2 * n)) else: # check not pure assert not np.allclose(np.linalg.det(cov_final), (hbar / 2)**(2 * n)) return cov_final, S_final
class TestRectangularSymmetricDecomposition: """Tests for linear interferometer decomposition into rectangular grid of phase-shifters and pairs of symmetric beamsplitters""" def test_unitary_validation(self): """Test that an exception is raised if not unitary""" A = np.random.random([5, 5]) + 1j * np.random.random([5, 5]) with pytest.raises(ValueError, match="matrix is not unitary"): dec.rectangular_symmetric(A) @pytest.mark.parametrize( "U", [ pytest.param(np.identity(2), id="identity2"), pytest.param(np.identity(2)[::-1], id="antiidentity2"), pytest.param(haar_measure(2), id="random2"), pytest.param(np.identity(4), id="identity4"), pytest.param(np.identity(3)[::-1], id="antiidentity4"), pytest.param(haar_measure(4), id="random4"), pytest.param(np.identity(8), id="identity8"), pytest.param(np.identity(8)[::-1], id="antiidentity8"), pytest.param(haar_measure(8), id="random8"), pytest.param(np.identity(20), id="identity20"), pytest.param(np.identity(20)[::-1], id="antiidentity20"), pytest.param(haar_measure(20), id="random20"), ], ) def test_decomposition(self, U, tol): """This test checks the function :func:`dec.rectangular_symmetric` for various unitary matrices. A given unitary (identity or random draw from Haar measure) is decomposed using the function :func:`dec.rectangular_symmetric` and the resulting beamsplitters are multiplied together. Test passes if the product matches the given unitary. """ nmax, mmax = U.shape assert nmax == mmax tlist, diags, _ = dec.rectangular_symmetric(U) qrec = np.identity(nmax) for i in tlist: assert i[2] >= 0 and i[2] < 2 * np.pi # internal phase assert i[3] >= 0 and i[3] < 2 * np.pi # external phase qrec = dec.mach_zehnder(*i) @ qrec qrec = np.diag(diags) @ qrec assert np.allclose(U, qrec, atol=tol, rtol=0)
class TestTriangularCompactDecomposition: """Tests for linear interferometer decomposition into rectangular grid of phase-shifters and pairs of symmetric beamsplitters""" def test_unitary_validation(self): """Test that an exception is raised if not unitary""" A = np.random.random([5, 5]) + 1j * np.random.random([5, 5]) with pytest.raises(ValueError, match="The input matrix is not unitary"): dec.triangular_compact(A) @pytest.mark.parametrize( "U", [ pytest.param(np.identity(2), id="identity2"), pytest.param(np.identity(2)[::-1], id="antiidentity2"), pytest.param(haar_measure(2), id="random2"), pytest.param(np.identity(4), id="identity4"), pytest.param(np.identity(4)[::-1], id="antiidentity4"), pytest.param(haar_measure(4), id="random4"), pytest.param(np.identity(8), id="identity8"), pytest.param(np.identity(8)[::-1], id="antiidentity8"), pytest.param(haar_measure(8), id="random8"), pytest.param(np.identity(20), id="identity20"), pytest.param(np.identity(20)[::-1], id="antiidentity20"), pytest.param(haar_measure(20), id="random20"), pytest.param(np.identity(7), id="identity7"), pytest.param(np.identity(7)[::-1], id="antiidentity7"), pytest.param(haar_measure(7), id="random7"), ], ) def test_decomposition(self, U, tol): """This test checks the function :func:`dec.rectangular_symmetric` for various unitary matrices. A given unitary (identity or random draw from Haar measure) is decomposed using the function :func:`dec.rectangular_symmetric` and the resulting beamsplitters are multiplied together. Test passes if the product matches the given unitary. """ nmax, mmax = U.shape assert nmax == mmax phases = dec.triangular_compact(U) Uout = _triangular_compact_recompose(phases) assert np.allclose(U, Uout, atol=tol, rtol=0)
def test_random_unitary(self, tol): """This test checks the rectangular decomposition for a random unitary. A random unitary is drawn from the Haar measure, then is decomposed via the rectangular decomposition of Clements et al., and the resulting beamsplitters are multiplied together. Test passes if the product matches the drawn unitary. """ # TODO: this test currently uses the T and Ti functions used to compute # Clements as the comparison. Probably should be changed. n = 20 U = haar_measure(n) tlist, diags, _ = dec.triangular(U) qrec = np.diag(diags) for i in tlist: qrec = dec.Ti(*i) @ qrec assert np.allclose(U, qrec, atol=tol, rtol=0)
def test_random_unitary_phase_end(self, tol): """This test checks the rectangular decomposition with phases at the end. A random unitary is drawn from the Haar measure, then is decomposed using Eq. 5 of the rectangular decomposition procedure of Clements et al, i.e., moving all the phases to the end of the interferometer. The resulting beamsplitters are multiplied together. Test passes if the product matches the drawn unitary. """ n = 20 U = haar_measure(n) tlist, diags, _ = dec.rectangular_phase_end(U) qrec = np.identity(n) for i in tlist: qrec = dec.T(*i) @ qrec qrec = np.diag(diags) @ qrec assert np.allclose(U, qrec, atol=tol, rtol=0)
class TestRectangularDecomposition: """Tests for linear interferometer rectangular decomposition""" def test_unitary_validation(self): """Test that an exception is raised if not unitary""" A = np.random.random([5, 5]) + 1j * np.random.random([5, 5]) with pytest.raises(ValueError, match="matrix is not unitary"): dec.rectangular(A) @pytest.mark.parametrize( "U", [ pytest.param(np.identity(20), id="identity20"), pytest.param(np.identity(20)[::-1], id="antiidentity20"), pytest.param(haar_measure(20), id="random20"), ], ) def test_rectangular(self, U, tol): """This test checks the function :func:`dec.rectangular` for various unitary matrices. A given unitary (identity or random draw from Haar measure) is decomposed using the function :func:`dec.rectangular` and the resulting beamsplitters are multiplied together. Test passes if the product matches the given unitary. """ nmax, mmax = U.shape assert nmax == mmax tilist, diags, tlist = dec.rectangular(U) qrec = np.identity(nmax) for i in tilist: qrec = dec.T(*i) @ qrec qrec = np.diag(diags) @ qrec for i in reversed(tlist): qrec = dec.Ti(*i) @ qrec assert np.allclose(U, qrec, atol=tol, rtol=0) def test_random_unitary_phase_end(self, tol): """This test checks the rectangular decomposition with phases at the end. A random unitary is drawn from the Haar measure, then is decomposed using Eq. 5 of the rectangular decomposition procedure of Clements et al, i.e., moving all the phases to the end of the interferometer. The resulting beamsplitters are multiplied together. Test passes if the product matches the drawn unitary. """ n = 20 U = haar_measure(n) tlist, diags, _ = dec.rectangular_phase_end(U) qrec = np.identity(n) for i in tlist: qrec = dec.T(*i) @ qrec qrec = np.diag(diags) @ qrec assert np.allclose(U, qrec, atol=tol, rtol=0) @pytest.mark.parametrize( "U", [ pytest.param(np.identity(20), id="identity20"), pytest.param(np.identity(20)[::-1], id="antiidentity20"), pytest.param(haar_measure(20), id="random20"), ], ) def test_rectangular_MZ(self, U, tol): """This test checks the function :func:`dec.rectangular_MZ` for various unitary matrices. A given unitary (identity or random draw from Haar measure) is decomposed using the function :func:`dec.rectangular_MZ` and the resulting beamsplitters are multiplied together. Test passes if the product matches the given unitary. """ nmax, mmax = U.shape assert nmax == mmax tilist, diags, tlist = dec.rectangular_MZ(U) qrec = np.identity(nmax) for i in tilist: qrec = dec.mach_zehnder(*i) @ qrec qrec = np.diag(diags) @ qrec for i in reversed(tlist): qrec = dec.mach_zehnder_inv(*i) @ qrec assert np.allclose(U, qrec, atol=tol, rtol=0)