Пример #1
0
    def test_loss_complete(self, hbar, tol):
        """Test full loss on half a TMS"""
        r = 0.543
        phi = 0.432
        T = 0

        S = symplectic.two_mode_squeezing(r, phi)
        mu = np.zeros([4])
        cov = S @ S.T * (hbar / 2)

        mu, cov = symplectic.loss(mu, cov, T, mode=0, hbar=hbar)

        # expected state mode 0
        expected0 = np.zeros([2]), np.identity(2) * hbar / 2
        res0 = symplectic.reduced_state(mu, cov, 0)

        # expected state mode 1
        nbar = np.sinh(r)**2
        expected1 = np.zeros([2]), np.identity(2) * (2 * nbar + 1) * hbar / 2
        res1 = symplectic.reduced_state(mu, cov, 1)

        assert np.allclose(res0[0], expected0[0], atol=tol, rtol=0)
        assert np.allclose(res0[1], expected0[1], atol=tol, rtol=0)

        assert np.allclose(res1[0], expected1[0], atol=tol, rtol=0)
        assert np.allclose(res1[1], expected1[1], atol=tol, rtol=0)
Пример #2
0
    def test_loss_complete_random(self, hbar, tol):
        """Test loss on random state"""
        T = 0

        mu = np.random.random(size=[4])
        cov = np.array([
            [10.4894171, 4.44832813, 7.35223928, -14.0593551],
            [4.44832813, 5.29244335, -1.48437419, -4.79381772],
            [7.35223928, -1.48437419, 11.92921345, -11.47687254],
            [-14.0593551, -4.79381772, -11.47687254, 19.67522694],
        ])

        res = symplectic.loss(mu, cov, T, mode=0, hbar=hbar)

        # the loss reduces the fractional mean photon number of mode 1
        mu_exp = mu.copy()
        mu_exp[0] = 0
        mu_exp[2] = 0
        cov_exp = np.array([
            [hbar / 2, 0, 0, 0],
            [0, 5.29244335, 0, -4.79381772],
            [0, 0, hbar / 2, 0],
            [0, -4.79381772, 0, 19.67522694],
        ])

        assert np.allclose(res[1], cov_exp, atol=tol, rtol=0)
        assert np.allclose(res[0], mu_exp, atol=tol, rtol=0)
Пример #3
0
    def test_displaced_loss_against_interferometer(self, hbar, tol):
        """Test that the loss channel on a displaced state corresponds to a beamsplitter
        acting on the mode with loss and an ancilla vacuum state"""
        T = 0.812

        alpha = np.random.random(size=[2]) + np.random.random(size=[2]) * 1j
        mu = np.concatenate([alpha.real, alpha.imag])

        # perform loss
        mu_res, _ = symplectic.loss(mu, np.identity(4), T, mode=0, hbar=hbar)

        # create a two mode beamsplitter acting on modes 0 and 2
        B = np.array([[np.sqrt(T), -np.sqrt(1 - T), 0, 0],
                      [np.sqrt(1 - T), np.sqrt(T), 0, 0],
                      [0, 0, np.sqrt(T), -np.sqrt(1 - T)],
                      [0, 0, np.sqrt(1 - T), np.sqrt(T)]])

        B = symplectic.expand(B, modes=[0, 2], N=3)

        # apply the beamsplitter to modes 0 and 2
        mu_expand = np.zeros([6])
        mu_expand[np.array([0, 1, 3, 4])] = mu
        mu_expected, _ = symplectic.reduced_state(B @ mu_expand,
                                                  np.identity(6),
                                                  modes=[0, 1])

        # compare loss function result to an interferometer mixing mode 0 with the vacuum
        assert np.allclose(mu_expected, mu_res, atol=tol, rtol=0)
Пример #4
0
    def test_loss_none(self, hbar, tol):
        """Test no loss on half a TMS leaves state unchanged"""
        r = 0.543
        phi = 0.432
        T = 1

        S = symplectic.two_mode_squeezing(r, phi)
        mu = np.zeros([4])
        cov = S @ S.T * (hbar / 2)

        res = symplectic.loss(mu, cov, T, mode=0, hbar=hbar)
        expected = mu, cov

        assert np.allclose(res[0], expected[0], atol=tol, rtol=0)
        assert np.allclose(res[1], expected[1], atol=tol, rtol=0)
Пример #5
0
def test_four_modes(hbar):
    """Test that probabilities are correctly updates for a four modes system under loss"""
    # All this block is to generate the correct covariance matrix.
    # It correnponds to num_modes=4 modes that undergo two mode squeezing between modes i and i + (num_modes / 2).
    # Then they undergo displacement.
    # The signal and idlers see and interferometer with unitary matrix u2x2.
    # And then they see loss by amount etas[i].
    num_modes = 4
    theta = 0.45
    phi = 0.7
    u2x2 = np.array([
        [np.cos(theta / 2),
         np.exp(1j * phi) * np.sin(theta / 2)],
        [-np.exp(-1j * phi) * np.sin(theta / 2),
         np.cos(theta / 2)],
    ])

    u4x4 = block_diag(u2x2, u2x2)

    cov = np.identity(2 * num_modes) * hbar / 2
    means = 0.5 * np.random.rand(2 * num_modes) * np.sqrt(hbar / 2)
    rs = [0.1, 0.9]
    n_half = num_modes // 2

    for i, r_val in enumerate(rs):
        Sexpanded = expand(two_mode_squeezing(r_val, 0.0), [i, n_half + i],
                           num_modes)
        cov = Sexpanded @ cov @ (Sexpanded.T)

    Su = expand(interferometer(u4x4), range(num_modes), num_modes)
    cov = Su @ cov @ (Su.T)
    cov_lossless = np.copy(cov)
    means_lossless = np.copy(means)
    etas = [0.9, 0.7, 0.9, 0.1]

    for i, eta in enumerate(etas):
        means, cov = loss(means, cov, eta, i, hbar=hbar)

    cutoff = 3
    probs_lossless = probabilities(means_lossless,
                                   cov_lossless,
                                   4 * cutoff,
                                   hbar=hbar)
    probs = probabilities(means, cov, cutoff, hbar=hbar)
    probs_updated = update_probabilities_with_loss(etas, probs_lossless)
    assert np.allclose(probs,
                       probs_updated[:cutoff, :cutoff, :cutoff, :cutoff],
                       atol=1e-6)
Пример #6
0
    def test_loss_thermal_state(self, hbar, tol):
        """Test loss on part of a thermal state"""
        nbar = np.array([0.4532, 0.123, 0.432])
        T = 0.54

        mu = np.zeros([2 * len(nbar)])
        cov = np.diag(2 * np.tile(nbar, 2) + 1) * (hbar / 2)

        res = symplectic.loss(mu, cov, T, mode=1, hbar=hbar)

        # the loss reduces the fractional mean photon number of mode 1
        new_nbar = nbar * np.array([1, T, 1])
        expected = mu, np.diag(2 * np.tile(new_nbar, 2) + 1) * (hbar / 2)

        assert np.allclose(res[0], expected[0], atol=tol, rtol=0)
        assert np.allclose(res[1], expected[1], atol=tol, rtol=0)
Пример #7
0
    def test_TMS_against_interferometer(self, hbar, tol):
        """Test that the loss channel on a TMS state corresponds to a beamsplitter
        acting on the mode with loss and an ancilla vacuum state"""
        r = 0.543
        phi = 0.432
        T = 0.812

        S = symplectic.two_mode_squeezing(r, phi)
        cov = S @ S.T * (hbar / 2)

        # perform loss
        _, cov_res = symplectic.loss(np.zeros([4]), cov, T, mode=0, hbar=hbar)

        # create a two mode beamsplitter acting on modes 0 and 2
        B = np.array([
            [np.sqrt(T), -np.sqrt(1 - T), 0, 0],
            [np.sqrt(1 - T), np.sqrt(T), 0, 0],
            [0, 0, np.sqrt(T), -np.sqrt(1 - T)],
            [0, 0, np.sqrt(1 - T), np.sqrt(T)],
        ])

        B = symplectic.expand(B, modes=[0, 2], N=3)

        # add an ancilla vacuum state in mode 2
        cov_expand = np.identity(6) * hbar / 2
        cov_expand[:2, :2] = cov[:2, :2]
        cov_expand[3:5, :2] = cov[2:, :2]
        cov_expand[:2, 3:5] = cov[:2, 2:]
        cov_expand[3:5, 3:5] = cov[2:, 2:]

        # apply the beamsplitter to modes 0 and 2
        cov_expand = B @ cov_expand @ B.T

        # compare loss function result to an interferometer mixing mode 0 with the vacuum
        _, cov_expected = symplectic.reduced_state(np.zeros([6]),
                                                   cov_expand,
                                                   modes=[0, 1])
        assert np.allclose(cov_expected, cov_res, atol=tol, rtol=0)