Exemple #1
0
def _program_in_CJ_rep(prog, cutoff_dim: int):
    """Convert a Program object to Choi-Jamiolkowski representation.

    Doubles the number of modes of a Program object and prepends to its circuit
    the preparation of the maximally entangled ket state.

    The core idea is that when we apply any quantum channel (e.g. a unitary gate)
    to the density matrix of the maximally entangled state, we obtain the Choi matrix
    of the channel as the result.

    If the channel is unitary, applying it on the maximally entangled ket yields
    the corresponding unitary matrix, reshaped.

    Args:
        prog (Program): quantum program
        cutoff_dim (int): the Fock basis truncation

    Returns:
        Program: modified program
    """
    prog = copy.deepcopy(prog)
    prog.locked = False  # unlock the copy so we can modify it
    N = prog.init_num_subsystems
    prog._add_subsystems(N)  # pylint: disable=protected-access
    prog.init_num_subsystems = 2 * N
    I = _interleaved_identities(N, cutoff_dim)
    # prepend the circuit with the I ket preparation
    prog.circuit.insert(0, Command(Ket(I), list(prog.reg_refs.values())))
    return prog
    def test_2mode_squeezed_vacuum_gradients(self, setup_eng, cutoff, tol,
                                             batch_size):
        """Tests whether the gradient for the probability of the states |0,0> and |1,1>
         created by an S2gate is correct."""
        if batch_size is not None:
            pytest.skip(
                "Cannot calculate gradient in batch mode, as tape.gradient "
                "cannot differentiate non-scalar output.")

        R = 0.3
        PHI = 0.2

        eng, prog = setup_eng(2)
        _r, _phi = prog.params("r", "phi")
        vacuum = np.zeros((cutoff, cutoff), dtype=np.complex64)
        vacuum[0, 0] = 1.0 + 0.0j

        with prog.context as q:
            Ket(vacuum) | (q[0], q[1])
            S2gate(_r, _phi) | (q[0], q[1])

        r = tf.Variable(R)
        phi = tf.Variable(PHI)

        with tf.GradientTape(persistent=True) as tape:
            state = eng.run(prog, args={"r": r, "phi": phi}).state
            prob00 = tf.abs(state.ket()[0, 0])**2
            prob11 = tf.abs(state.ket()[1, 1])**2

        r_grad, phi_grad = tape.gradient(prob00, [r, phi])
        assert np.allclose(r_grad,
                           -2 * np.tanh(R) / np.cosh(R)**2,
                           atol=tol,
                           rtol=0)
        assert np.allclose(phi_grad, 0.0, atol=tol, rtol=0)

        r_grad, phi_grad = tape.gradient(prob11, [r, phi])
        assert np.allclose(r_grad,
                           2 * (np.sinh(R) - np.sinh(R)**3) / np.cosh(R)**5,
                           atol=tol,
                           rtol=0)
        assert np.allclose(phi_grad, 0.0, atol=tol, rtol=0)
    def test_MZ_state_gradients(self, setup_eng, cutoff, tol, batch_size):
        """Tests whether the gradient for the state created by interfering two single photons at
        a beam splitter is correct."""
        if batch_size is not None:
            pytest.skip(
                "Cannot calculate gradient in batch mode, as tape.gradient "
                "cannot differentiate non-scalar output.")

        PHI_IN = 0.3
        PHI_EX = 0.2

        eng, prog = setup_eng(2)
        _phi_in, _phi_ex = prog.params("phi_in", "phi_ex")
        photon_11 = np.zeros((cutoff, cutoff), dtype=np.complex64)
        photon_11[1, 1] = 1.0 + 0.0j

        with prog.context as q:
            Ket(photon_11) | (q[0], q[1])
            MZgate(_phi_in, _phi_ex) | (q[0], q[1])

        phi_in = tf.Variable(PHI_IN)
        phi_ex = tf.Variable(PHI_EX)

        with tf.GradientTape(persistent=True) as tape:
            state = eng.run(prog, args={
                "phi_in": phi_in,
                "phi_ex": phi_ex
            }).state
            prob11 = tf.abs(state.ket()[1, 1])**2
            prob02 = tf.abs(state.ket()[0, 2])**2

        phi_in_grad, phi_ex_grad = tape.gradient(prob11, [phi_in, phi_ex])
        assert np.allclose(phi_in_grad, -np.sin(2 * PHI_IN), atol=tol, rtol=0)
        assert np.allclose(phi_ex_grad, 0, atol=tol, rtol=0)

        phi_in_grad, phi_ex_grad = tape.gradient(prob02, [phi_in, phi_ex])
        assert np.allclose(phi_in_grad,
                           np.sin(PHI_IN) * np.cos(PHI_IN),
                           atol=tol,
                           rtol=0)
        assert np.allclose(phi_ex_grad, 0, atol=tol, rtol=0)
    def test_BS_state_gradients(self, setup_eng, cutoff, tol, batch_size):
        """Tests whether the gradient for the state created by interfering two single photons at
        a beam splitter is correct."""
        if batch_size is not None:
            pytest.skip(
                "Cannot calculate gradient in batch mode, as tape.gradient "
                "cannot differentiate non-scalar output.")

        THETA = 0.3
        PHI = 0.2

        eng, prog = setup_eng(2)
        _theta, _phi = prog.params("theta", "phi")
        photon_11 = np.zeros((cutoff, cutoff), dtype=np.complex64)
        photon_11[1, 1] = 1.0 + 0.0j

        with prog.context as q:
            Ket(photon_11) | (q[0], q[1])
            BSgate(_theta, _phi) | (q[0], q[1])

        theta = tf.Variable(THETA)
        phi = tf.Variable(PHI)

        with tf.GradientTape(persistent=True) as tape:
            state = eng.run(prog, args={"theta": theta, "phi": phi}).state
            prob11 = tf.abs(state.ket()[1, 1])**2
            prob02 = tf.abs(state.ket()[0, 2])**2

        theta_grad, phi_grad = tape.gradient(prob11, [theta, phi])
        assert np.allclose(theta_grad,
                           -4 * np.sin(2 * THETA) * np.cos(2 * THETA),
                           atol=tol,
                           rtol=0)
        assert np.allclose(phi_grad, 0.0, atol=tol, rtol=0)

        theta_grad, phi_grad = tape.gradient(prob02, [theta, phi])
        assert np.allclose(theta_grad, np.sin(4 * THETA), atol=tol, rtol=0)
        assert np.allclose(phi_grad, 0.0, atol=tol, rtol=0)