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)
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