def test_mean_photon(self, tol, make_symmetric):
     """Test that the mean photon number is correct in graph_embed"""
     num_modes = 6
     A = np.random.random([num_modes, num_modes]) + 1j * np.random.random([num_modes, num_modes])
     if make_symmetric:
         A += A.T
     n_mean = 1.0
     sc, _, _ = dec.bipartite_graph_embed(A, mean_photon_per_mode=n_mean)
     n_mean_calc = np.sum(np.sinh(sc) ** 2) / (num_modes)
     assert np.allclose(n_mean, n_mean_calc, atol=tol, rtol=0)
    def test_correct_graph(self, tol, make_symmetric):
        """Test that the graph is embeded correctly"""
        num_modes = 3
        A = np.random.random([num_modes, num_modes]) + 1j * np.random.random([num_modes, num_modes])
        U, l, V = np.linalg.svd(A)
        new_l = np.array([np.tanh(np.arcsinh(np.sqrt(i))) for i in range(1, num_modes + 1)])
        n_mean = 0.5 * (num_modes + 1)
        if make_symmetric:
            At = U @ np.diag(new_l) @ U.T
        else:
            At = U @ np.diag(new_l) @ V.T
        sqf, Uf, Vf = dec.bipartite_graph_embed(At, mean_photon_per_mode=n_mean)

        assert np.allclose(np.tanh(-np.flip(sqf)), new_l)
        assert np.allclose(Uf @ np.diag(np.tanh(-sqf)) @ Vf.T, At)
 def test_square_validation(self):
     """Test that the graph_embed decomposition raises exception if not square"""
     A = np.random.random([4, 5]) + 1j * np.random.random([4, 5])
     with pytest.raises(ValueError, match="matrix is not square"):
         dec.bipartite_graph_embed(A)
示例#4
0
    def test_decomposition(self, tol):
        """Test that a graph is correctly decomposed"""
        n = 3
        prog = sf.Program(2*n)

        A = np.zeros([2*n, 2*n])
        B = np.random.random([n, n])

        A[:n, n:] = B
        A += A.T

        sq, U, V = dec.bipartite_graph_embed(B)

        G = ops.BipartiteGraphEmbed(A)
        cmds = G.decompose(prog.register)

        S = np.identity(4 * n)

        # calculating the resulting decomposed symplectic
        for cmd in cmds:
            # all operations should be BSgates, Rgates, or S2gates
            assert isinstance(
                cmd.op, (ops.Interferometer, ops.S2gate)
            )

            # build up the symplectic transform
            modes = [i.ind for i in cmd.reg]

            if isinstance(cmd.op, ops.S2gate):
                # check that the registers are i, i+n
                assert len(modes) == 2
                assert modes[1] == modes[0] + n

                r, phi = par_evaluate(cmd.op.p)
                assert -r in sq
                assert phi == 0

                S = _two_mode_squeezing(r, phi, modes, 2*n) @ S

            if isinstance(cmd.op, ops.Interferometer):
                # check that each unitary only applies to half the modes
                assert len(modes) == n
                assert modes in ([0, 1, 2], [3, 4, 5])

                # check matrix is unitary
                U1 = par_evaluate(cmd.op.p[0])
                assert np.allclose(U1 @ U1.conj().T, np.identity(n), atol=tol, rtol=0)

                if modes[0] == 0:
                    assert np.allclose(U1, U, atol=tol, rtol=0)
                else:
                    assert modes[0] == 3
                    assert np.allclose(U1, V, atol=tol, rtol=0)

                S_U = np.vstack(
                    [np.hstack([U1.real, -U1.imag]), np.hstack([U1.imag, U1.real])]
                )

                S = expand(S_U, modes, 2*n) @ S

        # the resulting covariance state
        cov = S @ S.T
        A_res = Amat(cov)[:2*n, :2*n]

        # The bottom right corner of A_res should be identical to A,
        # up to some constant scaling factor. Check if the ratio
        # of all elements is one
        ratio = np.real_if_close(A_res[n:, :n] / B.T)
        ratio /= ratio[0, 0]

        assert np.allclose(ratio, np.ones([n, n]), atol=tol, rtol=0)