Пример #1
0
    def test_interferometers(self, num_pairs, tol):
        """Test that the compilation correctly decomposes the interferometer using
        the rectangular_symmetric mesh"""
        prog = sf.Program(2 * num_pairs)
        U = random_interferometer(num_pairs)

        with prog.context as q:
            for i in range(0, num_pairs):
                ops.S2gate(SQ_AMPLITUDE) | (q[i], q[i + num_pairs])
            ops.Interferometer(U) | tuple(q[i] for i in range(num_pairs))
            ops.Interferometer(U) | tuple(
                q[i] for i in range(num_pairs, 2 * num_pairs))
            ops.MeasureFock() | q

        res = prog.compile(compiler="Xcov")

        expected = sf.Program(2 * num_pairs)

        with expected.context as q:
            for i in range(0, num_pairs):
                ops.S2gate(SQ_AMPLITUDE) | (q[i], q[i + num_pairs])
            ops.Interferometer(
                U, mesh="rectangular_symmetric", drop_identity=False) | tuple(
                    q[i] for i in range(num_pairs))
            ops.Interferometer(
                U, mesh="rectangular_symmetric", drop_identity=False) | tuple(
                    q[i] for i in range(num_pairs, 2 * num_pairs))
            ops.MeasureFock() | q

        expected = expected.compile(compiler=DummyCircuit())
        # Note that since DummyCircuit() has a hard coded limit of 8 modes we only check for this number
        assert program_equivalence(res,
                                   expected,
                                   atol=tol,
                                   compare_params=False)
Пример #2
0
    def test_missing_s2gates(self, num_pairs, tol):
        """Test identity S2gates are inserted when some (but not all)
        S2gates are included."""
        prog = sf.Program(2 * num_pairs)
        U = random_interferometer(num_pairs)
        assert num_pairs > 3
        with prog.context as q:
            ops.S2gate(SQ_AMPLITUDE) | (q[1], q[num_pairs + 1])
            ops.S2gate(SQ_AMPLITUDE) | (q[3], q[num_pairs + 3])
            ops.Interferometer(U) | tuple(q[i] for i in range(num_pairs))
            ops.Interferometer(U) | tuple(
                q[i] for i in range(num_pairs, 2 * num_pairs))
            ops.MeasureFock() | q

        expected = sf.Program(2 * num_pairs)

        with expected.context as q:
            ops.S2gate(SQ_AMPLITUDE) | (q[1], q[num_pairs + 1])
            ops.S2gate(0) | (q[0], q[num_pairs + 0])
            ops.S2gate(SQ_AMPLITUDE) | (q[3], q[num_pairs + 3])
            ops.S2gate(0) | (q[2], q[num_pairs + 2])
            ops.Interferometer(U) | tuple(q[i] for i in range(num_pairs))
            ops.Interferometer(U) | tuple(
                q[i] for i in range(num_pairs, 2 * num_pairs))
            ops.MeasureFock() | q

        res = prog.compile(compiler="Xcov")
        expected = expected.compile(compiler="Xcov")
        assert program_equivalence(res, expected, atol=tol)
Пример #3
0
    def test_no_s2gates(self, num_pairs, tol):
        """Test identity S2gates are inserted when no S2gates
        are provided."""
        prog = sf.Program(2 * num_pairs)
        U = random_interferometer(num_pairs)

        with prog.context as q:
            ops.Interferometer(U) | tuple(q[i] for i in range(num_pairs))
            ops.Interferometer(U) | tuple(
                q[i] for i in range(num_pairs, 2 * num_pairs))
            ops.MeasureFock() | q

        expected = sf.Program(2 * num_pairs)

        with expected.context as q:
            for i in range(num_pairs):
                ops.S2gate(0) | (q[i], q[i + num_pairs])
            ops.Interferometer(U) | tuple(q[i] for i in range(num_pairs))
            ops.Interferometer(U) | tuple(
                q[i] for i in range(num_pairs, 2 * num_pairs))
            ops.MeasureFock() | q

        res = prog.compile(compiler="Xcov")
        expected = expected.compile(compiler="Xcov")
        assert program_equivalence(res, expected, atol=tol)
Пример #4
0
    def test_no_s2gates(self, num_pairs, tol):
        """Test identity S2gates are inserted when no S2gates
        are provided."""
        prog = sf.Program(2 * num_pairs)
        U = random_interferometer(num_pairs)

        with prog.context as q:
            ops.Interferometer(U) | tuple(q[i] for i in range(num_pairs))
            ops.Interferometer(U) | tuple(
                q[i] for i in range(num_pairs, 2 * num_pairs))
            ops.MeasureFock() | q

        expected = sf.Program(2 * num_pairs)

        with expected.context as q:
            for i in range(num_pairs):
                ops.S2gate(0) | (q[i], q[i + num_pairs])
            ops.Interferometer(U) | tuple(q[i] for i in range(num_pairs))
            ops.Interferometer(U) | tuple(
                q[i] for i in range(num_pairs, 2 * num_pairs))
            ops.MeasureFock() | q

        # with pytest.raises(CircuitError, match="There can be no operations before the S2gates."):
        res = prog.compile(compiler="Xunitary")
        # with pytest.raises(CircuitError, match="There can be no operations before the S2gates."):
        expected = expected.compile(compiler="Xunitary")
        assert program_equivalence(res, expected, atol=tol)
Пример #5
0
    def test_exact_template(self, tol):
        """Test compilation works for the exact circuit"""
        bb = blackbird.loads(X8_CIRCUIT)
        bb = bb(
            squeezing_amplitude_0=SQ_AMPLITUDE,
            squeezing_amplitude_1=SQ_AMPLITUDE,
            squeezing_amplitude_2=SQ_AMPLITUDE,
            squeezing_amplitude_3=SQ_AMPLITUDE,
            phase_0=0,
            phase_1=1,
            phase_2=2,
            phase_3=3,
            phase_4=4,
            phase_5=5,
            phase_6=6,
            phase_7=7,
            phase_8=8,
            phase_9=9,
            phase_10=10,
            phase_11=11,
            final_phase_0=1.24,
            final_phase_1=-0.54,
            final_phase_2=4.12,
            final_phase_3=0,
            final_phase_4=1.24,
            final_phase_5=-0.54,
            final_phase_6=4.12,
            final_phase_7=0,
        )

        expected = to_program(bb)
        res = expected.compile(compiler="Xcov")

        assert program_equivalence(res,
                                   expected,
                                   atol=tol,
                                   compare_params=False)
Пример #6
0
    def test_no_unitary(self, tol):
        """Test compilation works with no unitary provided"""
        prog = sf.Program(8)

        with prog.context as q:
            ops.S2gate(SQ_AMPLITUDE) | (q[0], q[4])
            ops.S2gate(SQ_AMPLITUDE) | (q[1], q[5])
            ops.S2gate(SQ_AMPLITUDE) | (q[2], q[6])
            ops.S2gate(SQ_AMPLITUDE) | (q[3], q[7])
            ops.MeasureFock() | q

        res = prog.compile(compiler="Xcov")
        expected = sf.Program(8)

        with expected.context as q:
            ops.S2gate(SQ_AMPLITUDE, 0) | (q[0], q[4])
            ops.S2gate(SQ_AMPLITUDE, 0) | (q[1], q[5])
            ops.S2gate(SQ_AMPLITUDE, 0) | (q[2], q[6])
            ops.S2gate(SQ_AMPLITUDE, 0) | (q[3], q[7])

            # corresponds to an identity on modes [0, 1, 2, 3]
            # This can be easily seen from below by noting that:
            # MZ(pi, pi) = R(0) = I
            # MZ(pi, 0) @ MZ(pi, 0) = I
            # [R(pi) \otimes I] @ MZ(pi, 0) = I
            ops.MZgate(np.pi, 0) | (q[0], q[1])
            ops.MZgate(np.pi, 0) | (q[2], q[3])
            ops.MZgate(np.pi, np.pi) | (q[1], q[2])
            ops.MZgate(np.pi, np.pi) | (q[0], q[1])
            ops.MZgate(np.pi, 0) | (q[2], q[3])
            ops.MZgate(np.pi, np.pi) | (q[1], q[2])
            ops.Rgate(np.pi) | (q[0])
            ops.Rgate(0) | (q[1])
            ops.Rgate(0) | (q[2])
            ops.Rgate(0) | (q[3])

            # corresponds to an identity on modes [4, 5, 6, 7]
            ops.MZgate(np.pi, 0) | (q[4], q[5])
            ops.MZgate(np.pi, 0) | (q[6], q[7])
            ops.MZgate(np.pi, np.pi) | (q[5], q[6])
            ops.MZgate(np.pi, np.pi) | (q[4], q[5])
            ops.MZgate(np.pi, 0) | (q[6], q[7])
            ops.MZgate(np.pi, np.pi) | (q[5], q[6])
            ops.Rgate(np.pi) | (q[4])
            ops.Rgate(0) | (q[5])
            ops.Rgate(0) | (q[6])
            ops.Rgate(0) | (q[7])

            ops.MeasureFock() | q

        assert program_equivalence(res,
                                   expected,
                                   atol=tol,
                                   compare_params=False)

        # double check that the applied symplectic is correct

        # remove the Fock measurements
        res.circuit = res.circuit[:-1]

        # extract the Gaussian symplectic matrix
        O = res.compile(compiler="gaussian_unitary").circuit[0].op.p[0]

        # construct the expected symplectic matrix corresponding
        # to just the initial two mode squeeze gates
        S = two_mode_squeezing(SQ_AMPLITUDE, 0)
        num_modes = 8
        expected = np.identity(2 * num_modes)
        for i in range(num_modes // 2):
            expected = expand(S, [i, i + num_modes // 2], num_modes) @ expected
        # Note that the comparison has to be made at the level of covariance matrices
        # Not at the level of symplectic matrices
        assert np.allclose(O @ O.T, expected @ expected.T, atol=tol)
Пример #7
0
 def test_exact_template(self, tol):
     """Test compilation works for the exact circuit"""
     params = generate_X8_params(1, 0.3)
     prog = X8_device.create_program(**params)
     prog2 = prog.compile(device=X8_device, compiler="Xstrict")
     assert program_equivalence(prog, prog2, atol=tol, rtol=0)