def test_circuit_reexecution(backend):
    """Test re-executing a circuit with `gates.NoiseChnanel`."""
    original_backend = qibo.get_backend()
    qibo.set_backend(backend)
    c = models.Circuit(2)
    c.add(gates.H(0))
    c.add(gates.H(1))
    c.add(gates.NoiseChannel(0, px=0.5))
    c.add(gates.NoiseChannel(1, pz=0.3))
    final_rho = c().numpy()
    final_rho2 = c().numpy()
    np.testing.assert_allclose(final_rho, final_rho2)
    qibo.set_backend(original_backend)
def test_circuit_with_noise_noise_map():
    """Check ``circuit.with_noise() when giving noise map."""
    original_backend = qibo.get_backend()
    qibo.set_backend("matmuleinsum")
    noise_map = {0: (0.1, 0.2, 0.1), 1: (0.2, 0.3, 0.0),
                 2: (0.0, 0.0, 0.0)}

    c = models.Circuit(3)
    c.add([gates.H(0), gates.H(1), gates.X(2)])
    c.add(gates.M(2))
    noisy_c = c.with_noise(noise_map, measurement_noise = (0.3, 0.0, 0.0))

    target_c = models.Circuit(3)
    target_c.add(gates.H(0))
    target_c.add(gates.NoiseChannel(0, 0.1, 0.2, 0.1))
    target_c.add(gates.NoiseChannel(1, 0.2, 0.3, 0.0))
    target_c.add(gates.H(1))
    target_c.add(gates.NoiseChannel(0, 0.1, 0.2, 0.1))
    target_c.add(gates.NoiseChannel(1, 0.2, 0.3, 0.0))
    target_c.add(gates.X(2))
    target_c.add(gates.NoiseChannel(0, 0.1, 0.2, 0.1))
    target_c.add(gates.NoiseChannel(1, 0.2, 0.3, 0.0))
    target_c.add(gates.NoiseChannel(2, 0.3, 0.0, 0.0))

    final_state = noisy_c().numpy()
    target_state = target_c().numpy()
    np.testing.assert_allclose(target_state, final_state)
    qibo.set_backend(original_backend)
def test_circuit_with_noise_exception():
    """Check that calling ``with_noise`` in a noisy circuit raises error."""
    original_backend = qibo.get_backend()
    qibo.set_backend("matmuleinsum")
    c = models.Circuit(2)
    c.add([gates.H(0), gates.H(1), gates.NoiseChannel(0, px=0.2)])
    with pytest.raises(ValueError):
        noisy_c = c.with_noise((0.2, 0.3, 0.0))
    qibo.set_backend(original_backend)
def test_tensorflow_channel_errors():
    import tensorflow as tf
    original_backend = qibo.get_backend()
    qibo.set_backend("matmuleinsum")
    gate = gates.NoiseChannel(0, 0.1, 0.2, 0.3)
    state = tf.cast(np.random.random(4 * (2,)), dtype=tf.complex128)
    with pytest.raises(ValueError):
        state = gate(state, is_density_matrix=False)
    state = gate(state)
    qibo.set_backend(original_backend)
def test_circuit_with_noise_execution():
    """Check ``circuit.with_noise()`` execution."""
    original_backend = qibo.get_backend()
    qibo.set_backend("matmuleinsum")
    c = models.Circuit(2)
    c.add([gates.H(0), gates.H(1)])
    noisy_c = c.with_noise((0.1, 0.2, 0.3))

    target_c = models.Circuit(2)
    target_c.add(gates.H(0))
    target_c.add(gates.NoiseChannel(0, 0.1, 0.2, 0.3))
    target_c.add(gates.NoiseChannel(1, 0.1, 0.2, 0.3))
    target_c.add(gates.H(1))
    target_c.add(gates.NoiseChannel(0, 0.1, 0.2, 0.3))
    target_c.add(gates.NoiseChannel(1, 0.1, 0.2, 0.3))

    final_state = noisy_c().numpy()
    target_state = target_c().numpy()
    np.testing.assert_allclose(target_state, final_state)
    qibo.set_backend(original_backend)
def test_circuit_switch_to_density_matrix(backend):
    """Test that using `gates.NoiseChnanel` switches vector to density matrix."""
    original_backend = qibo.get_backend()
    qibo.set_backend(backend)
    c = models.Circuit(2)
    c.add(gates.H(0))
    c.add(gates.H(1))
    c.add(gates.NoiseChannel(0, px=0.5))
    c.add(gates.NoiseChannel(1, pz=0.3))
    final_rho = c().numpy()

    psi = np.ones(4) / 2
    initial_rho = np.outer(psi, psi.conj())
    c = models.Circuit(2)
    c.add(gates.NoiseChannel(0, px=0.5))
    c.add(gates.NoiseChannel(1, pz=0.3))
    target_rho = c(initial_rho).numpy()

    np.testing.assert_allclose(final_rho, target_rho)
    qibo.set_backend(original_backend)
def ansatz(p=0):
    """Ansatz for driving a random state into its up-tp-phases canonical form.

      Args:
        p (float): probability of occuring a single-qubit depolarizing error

      Returns:
        Qibo circuit implementing the variational ansatz.
    """
    C = Circuit(3)
    for i in range(3):
        C.add(gates.RZ(i, theta=0))
        C.add(gates.RY(i, theta=0))
        C.add(gates.RZ(i, theta=0))
        if p > 0:
            C.add(gates.NoiseChannel(i, px=p / 3, py=p / 3, pz=p / 3))
    for i in range(3):
        if p > 0:
            C.add(gates.NoiseChannel(i, px=10 * p))
        C.add(gates.M(i))
    return C
def test_circuit_with_noise_with_measurements():
    """Check ``circuit.with_noise() when using measurement noise."""
    original_backend = qibo.get_backend()
    qibo.set_backend("matmuleinsum")
    c = models.Circuit(2)
    c.add([gates.H(0), gates.H(1)])
    c.add(gates.M(0))
    noisy_c = c.with_noise(3 * (0.1,), measurement_noise = (0.3, 0.0, 0.0))

    target_c = models.Circuit(2)
    target_c.add(gates.H(0))
    target_c.add(gates.NoiseChannel(0, 0.1, 0.1, 0.1))
    target_c.add(gates.NoiseChannel(1, 0.1, 0.1, 0.1))
    target_c.add(gates.H(1))
    target_c.add(gates.NoiseChannel(0, 0.3, 0.0, 0.0))
    target_c.add(gates.NoiseChannel(1, 0.1, 0.1, 0.1))

    final_state = noisy_c().numpy()
    target_state = target_c().numpy()
    np.testing.assert_allclose(target_state, final_state)
    qibo.set_backend(original_backend)
def test_controlled_by_channel():
    """Test that attempting to control channels raises error."""
    original_backend = qibo.get_backend()
    qibo.set_backend("matmuleinsum")
    c = models.Circuit(2)
    with pytest.raises(ValueError):
        c.add(gates.NoiseChannel(0, px=0.5).controlled_by(1))

    a1 = np.sqrt(0.4) * np.array([[0, 1], [1, 0]])
    a2 = np.sqrt(0.6) * np.array([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 0, 1],
                                  [0, 0, 1, 0]])
    config = [((1,), a1), ((0, 1), a2)]
    with pytest.raises(ValueError):
        gate = gates.GeneralChannel(config).controlled_by(1)
    qibo.set_backend(original_backend)
def test_bitflip_noise(backend):
    """Test `gates.NoiseChannel` on random initial density matrix."""
    original_backend = qibo.get_backend()
    qibo.set_backend(backend)
    initial_rho = random_density_matrix(2)

    c = models.Circuit(2)
    c.add(gates.NoiseChannel(1, px=0.3))
    final_rho = c(np.copy(initial_rho)).numpy()

    c = models.Circuit(2)
    c.add(gates.X(1))
    target_rho = 0.3 * c(np.copy(initial_rho)).numpy()
    target_rho += 0.7 * initial_rho.reshape(target_rho.shape)

    np.testing.assert_allclose(final_rho, target_rho)
    qibo.set_backend(original_backend)
Example #11
0
    def with_noise(
            self,
            noise_map: NoiseMapType,
            measurement_noise: Optional[NoiseMapType] = None) -> "BaseCircuit":
        """Creates a copy of the circuit with noise gates after each gate.

        Args:
            noise_map (dict): Dictionary that maps qubit ids to noise
                probabilities (px, py, pz).
                If a tuple of probabilities (px, py, pz) is given instead of
                a dictionary, then the same probabilities will be used for all
                qubits.
            measurement_noise (dict): Optional map for using different noise
                probabilities before measurement for the qubits that are
                measured.
                If ``None`` the default probabilities specified by ``noise_map``
                will be used for all qubits.

        Returns:
            Circuit object that contains all the gates of the original circuit
            and additional noise channels on all qubits after every gate.

        Example:
            ::

                from qibo.models import Circuit
                from qibo import gates
                c = Circuit(2)
                c.add([gates.H(0), gates.H(1), gates.CNOT(0, 1)])
                noise_map = {0: (0.1, 0.0, 0.2), 1: (0.0, 0.2, 0.1)}
                noisy_c = c.with_noise(noise_map)

                # ``noisy_c`` will be equivalent to the following circuit
                c2 = Circuit(2)
                c2.add(gates.H(0))
                c2.add(gates.NoiseChannel(0, 0.1, 0.0, 0.2))
                c2.add(gates.NoiseChannel(1, 0.0, 0.2, 0.1))
                c2.add(gates.H(1))
                c2.add(gates.NoiseChannel(0, 0.1, 0.0, 0.2))
                c2.add(gates.NoiseChannel(1, 0.0, 0.2, 0.1))
                c2.add(gates.CNOT(0, 1))
                c2.add(gates.NoiseChannel(0, 0.1, 0.0, 0.2))
                c2.add(gates.NoiseChannel(1, 0.0, 0.2, 0.1))
        """
        noise_map = self._check_noise_map(noise_map)
        if measurement_noise is not None:
            if self.measurement_gate is None:
                raise_error(
                    ValueError, "Passed measurement noise but the circuit "
                    "does not contain measurement gates.")
            measurement_noise = self._check_noise_map(measurement_noise)
            # apply measurement noise only to the qubits that are measured
            # and leave default noise to the rest
            measured_qubits = set(self.measurement_gate.target_qubits)
            measurement_noise = {
                q:
                measurement_noise[q] if q in measured_qubits else noise_map[q]
                for q in range(self.nqubits)
            }

        # Generate noise gates
        noise_gates = []
        for gate in self.queue:
            if isinstance(gate, gates.NoiseChannel):
                raise_error(
                    ValueError, "`.with_noise` method is not available for "
                    "circuits that already contain noise channels.")
            noise_gates.append([
                gate_module.NoiseChannel(q, *list(p))
                for q, p in noise_map.items() if sum(p) > 0
            ])
        if measurement_noise is not None:
            noise_gates[-1] = [
                gate_module.NoiseChannel(q, *list(p))
                for q, p in measurement_noise.items() if sum(p) > 0
            ]

        # Create new circuit with noise gates inside
        noisy_circuit = self.__class__(self.nqubits)
        for i, gate in enumerate(self.queue):
            # Do not use `circuit.add` here because these gates are already
            # added in the original circuit
            noisy_circuit.queue.append(gate)
            for noise_gate in noise_gates[i]:
                noisy_circuit.add(noise_gate)
        noisy_circuit.measurement_tuples = dict(self.measurement_tuples)
        noisy_circuit.measurement_gate = self.measurement_gate
        return noisy_circuit