コード例 #1
0
 def test_passive_merging_inverse(self, M, tol):
     """test merging of two passive channels which should return identity"""
     T1 = np.random.randn(M, M) + 1j * np.random.randn(M, M)
     T2 = np.linalg.inv(T1)
     G = ops.PassiveChannel(T1)
     merged = G.merge(ops.PassiveChannel(T2))
     assert merged is None
コード例 #2
0
 def test_passive_merging(self, M, tol):
     """test merging of two passive channels"""
     T1 = np.random.randn(M, M) + 1j * np.random.randn(M, M)
     T2 = np.random.randn(M, M) + 1j * np.random.randn(M, M)
     G = ops.PassiveChannel(T1)
     merged = G.merge(ops.PassiveChannel(T2))
     assert np.allclose(merged.p[0], T2 @ T1, atol=tol, rtol=0)
コード例 #3
0
    def test_passive_channel_vacuum(self, M, setup_eng, tol):
        """test that you get vacuum on all modes if you apply a channel with all zero"""
        eng, prog = setup_eng(M)

        with prog.context as q:
            for i in range(M):
                ops.Dgate(abs(A), np.angle(A)) | q[i]
            ops.PassiveChannel(np.zeros((M, M))) | q

        eng.run(prog)
        assert np.all(eng.backend.is_vacuum(tol))
コード例 #4
0
def test_all_passive_gates(hbar, tol):
    """test that all gates run and do not cause anything to crash"""

    eng = sf.LocalEngine(backend="gaussian")
    circuit = sf.Program(4)

    with circuit.context as q:
        for i in range(4):
            ops.Sgate(1, 0.3) | q[i]
        ops.Rgate(np.pi) | q[0]
        ops.PassiveChannel(np.ones((2, 2))) | (q[1], q[2])
        ops.LossChannel(0.9) | q[1]
        ops.MZgate(0.25 * np.pi, 0) | (q[2], q[3])
        ops.PassiveChannel(np.array([[0.83]])) | q[0]
        ops.sMZgate(0.11, -2.1) | (q[0], q[3])
        ops.Interferometer(np.array([[np.exp(1j * 2)]])) | q[1]
        ops.BSgate(0.8, 0.4) | (q[1], q[3])
        ops.Interferometer(0.5**0.5 * np.fft.fft(np.eye(2))) | (q[0], q[2])
        ops.PassiveChannel(0.1 * np.ones((3, 3))) | (q[3], q[1], q[0])

    cov = eng.run(circuit).state.cov()

    circuit = sf.Program(4)
    with circuit.context as q:
        ops.Rgate(np.pi) | q[0]
        ops.PassiveChannel(np.ones((2, 2))) | (q[1], q[2])
        ops.LossChannel(0.9) | q[1]
        ops.MZgate(0.25 * np.pi, 0) | (q[2], q[3])
        ops.PassiveChannel(np.array([[0.83]])) | q[0]
        ops.sMZgate(0.11, -2.1) | (q[0], q[3])
        ops.Interferometer(np.array([[np.exp(1j * 2)]])) | q[1]
        ops.BSgate(0.8, 0.4) | (q[1], q[3])
        ops.Interferometer(0.5**0.5 * np.fft.fft(np.eye(2))) | (q[0], q[2])
        ops.PassiveChannel(0.1 * np.ones((3, 3))) | (q[3], q[1], q[0])

    compiled_circuit = circuit.compile(compiler="passive")
    T = compiled_circuit.circuit[0].op.p[0]

    S_sq = np.eye(8, dtype=np.complex128)
    r = 1
    phi = 0.3
    for i in range(4):
        S_sq[i, i] = np.cosh(r) - np.sinh(r) * np.cos(phi)
        S_sq[i, i + 4] = -np.sinh(r) * np.sin(phi)
        S_sq[i + 4, i] = -np.sinh(r) * np.sin(phi)
        S_sq[i + 4, i + 4] = np.cosh(r) + np.sinh(r) * np.cos(phi)

    cov_sq = (hbar / 2) * S_sq @ S_sq.T
    mu = np.zeros(8)

    P = interferometer(T)
    L = (hbar / 2) * (np.eye(P.shape[0]) - P @ P.T)
    cov2 = P @ cov_sq @ P.T + L

    assert np.allclose(cov, cov2, atol=tol, rtol=0)
コード例 #5
0
    def test_passive_channel(self, M, setup_eng, tol):
        """check that passive channel is consistent with unitary methods"""
        U = unitary_group.rvs(M)

        loss_in = np.random.random(M)
        loss_out = np.random.random(M)

        T = (np.sqrt(loss_in) * U) * np.sqrt(loss_out[np.newaxis].T)

        eng, prog = setup_eng(M)
        with prog.context as q:
            for i in range(M):
                ops.Sgate(1) | q[i]
                ops.Dgate(A) | q[i]
            ops.PassiveChannel(T) | q

        state = eng.run(prog).state
        cov1 = state.cov()
        mu1 = state.means()

        eng, prog = setup_eng(M)
        with prog.context as q:
            for i in range(M):
                ops.Sgate(1) | q[i]
                ops.Dgate(A) | q[i]
                ops.LossChannel(loss_in[i]) | q[i]
            ops.Interferometer(U) | q
            for i in range(M):
                ops.LossChannel(loss_out[i]) | q[i]

        state = eng.run(prog).state
        cov2 = state.cov()
        mu2 = state.means()

        assert np.allclose(cov1, cov2, atol=tol, rtol=0)
        assert np.allclose(mu1, mu2, atol=tol, rtol=0)

        u, s, v = np.linalg.svd(T)

        eng, prog = setup_eng(M)
        with prog.context as q:
            for i in range(M):
                ops.Sgate(1) | q[i]
                ops.Dgate(A) | q[i]
            ops.Interferometer(v) | q
            for i in range(M):
                ops.LossChannel(s[i]**2) | q[i]
            ops.Interferometer(u) | q

        state = eng.run(prog).state
        cov3 = state.cov()
        mu3 = state.means()

        assert np.allclose(cov1, cov3, atol=tol, rtol=0)
        assert np.allclose(mu1, mu3, atol=tol, rtol=0)

        T1 = u * s
        eng, prog = setup_eng(M)
        with prog.context as q:
            for i in range(M):
                ops.Sgate(1) | q[i]
                ops.Dgate(A) | q[i]
            ops.PassiveChannel(v) | q
            ops.PassiveChannel(T1) | q

        state = eng.run(prog).state
        cov4 = state.cov()
        mu4 = state.means()

        assert np.allclose(cov1, cov4, atol=tol, rtol=0)
        assert np.allclose(mu1, mu4, atol=tol, rtol=0)
コード例 #6
0
    def compile(self, seq, registers):
        """Try to arrange a passive circuit into a single multimode passive operation

        This method checks whether the circuit can be implemented as a sequence of passive gates.
        If the answer is yes it arranges them into a single operation.

        Args:
            seq (Sequence[Command]): passive quantum circuit to modify
            registers (Sequence[RegRefs]): quantum registers
        Returns:
            List[Command]: compiled circuit
        Raises:
            CircuitError: the circuit does not correspond to a passive unitary
        """

        # Check which modes are actually being used
        used_modes = []
        for operations in seq:
            modes = [modes_label.ind for modes_label in operations.reg]
            used_modes.append(modes)

        used_modes = list(
            set(item for sublist in used_modes for item in sublist))

        # dictionary mapping the used modes to consecutive non-negative integers
        dict_indices = {used_modes[i]: i for i in range(len(used_modes))}
        nmodes = len(used_modes)

        # We start with an identity then sequentially update with the gate transformations
        T = np.identity(nmodes, dtype=np.complex128)

        # Now we will go through each operation in the sequence `seq` and apply it to T
        for operations in seq:
            name = operations.op.__class__.__name__
            params = par_evaluate(operations.op.p)
            modes = [modes_label.ind for modes_label in operations.reg]
            if name == "Rgate":
                G = np.exp(1j * params[0])
                T = _apply_one_mode_gate(G, T, dict_indices[modes[0]])
            elif name == "LossChannel":
                G = np.sqrt(params[0])
                T = _apply_one_mode_gate(G, T, dict_indices[modes[0]])
            elif name == "Interferometer":
                U = params[0]
                if U.shape == (1, 1):
                    T = _apply_one_mode_gate(U[0, 0], T,
                                             dict_indices[modes[0]])
                elif U.shape == (2, 2):
                    T = _apply_two_mode_gate(U, T, dict_indices[modes[0]],
                                             dict_indices[modes[1]])
                else:
                    modes = [dict_indices[mode] for mode in modes]
                    U_expand = np.eye(nmodes, dtype=np.complex128)
                    U_expand[np.ix_(modes, modes)] = U
                    T = U_expand @ T
            elif name == "PassiveChannel":
                T0 = params[0]
                if T0.shape == (1, 1):
                    T = _apply_one_mode_gate(T0[0, 0], T,
                                             dict_indices[modes[0]])
                elif T0.shape == (2, 2):
                    T = _apply_two_mode_gate(T0, T, dict_indices[modes[0]],
                                             dict_indices[modes[1]])
                else:
                    modes = [dict_indices[mode] for mode in modes]
                    T0_expand = np.eye(nmodes, dtype=np.complex128)
                    T0_expand[np.ix_(modes, modes)] = T0
                    T = T0_expand @ T
            elif name == "BSgate":
                G = _beam_splitter_passive(params[0], params[1])
                T = _apply_two_mode_gate(G, T, dict_indices[modes[0]],
                                         dict_indices[modes[1]])
            elif name == "MZgate":
                v = np.exp(1j * params[0])
                u = np.exp(1j * params[1])
                U = 0.5 * np.array([[u * (v - 1), 1j *
                                     (1 + v)], [1j * u * (1 + v), 1 - v]])
                T = _apply_two_mode_gate(U, T, dict_indices[modes[0]],
                                         dict_indices[modes[1]])
            elif name == "sMZgate":
                exp_sigma = np.exp(1j * (params[0] + params[1]) / 2)
                delta = (params[0] - params[1]) / 2
                U = exp_sigma * np.array([[np.sin(delta),
                                           np.cos(delta)],
                                          [np.cos(delta), -np.sin(delta)]])
                T = _apply_two_mode_gate(U, T, dict_indices[modes[0]],
                                         dict_indices[modes[1]])

        ord_reg = [r for r in list(registers) if r.ind in used_modes]
        ord_reg = sorted(list(ord_reg), key=lambda x: x.ind)

        return [Command(ops.PassiveChannel(T), ord_reg)]