def test_post_measurement_bitflips_on_circuit_result(backend):
    """Check bitflip errors on ``CircuitResult`` objects."""
    original_backend = qibo.get_backend()
    qibo.set_backend(backend)
    thetas = np.random.random(4)
    c = models.Circuit(4)
    c.add((gates.RX(i, theta=t) for i, t in enumerate(thetas)))
    c.add(gates.M(0, 1, register_name="a"))
    c.add(gates.M(3, register_name="b"))
    result = c(nshots=30)
    samples = result.samples()
    K.set_seed(123)
    noisy_result = result.copy().apply_bitflips({0: 0.2, 1: 0.4, 3: 0.3})
    noisy_samples = noisy_result.samples(binary=True)
    register_samples = noisy_result.samples(binary=True, registers=True)

    K.set_seed(123)
    sprobs = np.array(K.random_uniform(samples.shape))
    flipper = sprobs < np.array([0.2, 0.4, 0.3])
    target_samples = (samples + flipper) % 2
    np.testing.assert_allclose(noisy_samples, target_samples)
    # Check register samples
    np.testing.assert_allclose(register_samples["a"], target_samples[:, :2])
    np.testing.assert_allclose(register_samples["b"], target_samples[:, 2:])
    qibo.set_backend(original_backend)
Example #2
0
def test_measurementresult_apply_bitflips_random_samples(backend, probs):
    qubits = tuple(range(4))
    samples = np.random.randint(0, 2, (20, 4))
    result = measurements.MeasurementResult(qubits)
    result.binary = K.cast(np.copy(samples))
    K.set_seed(123)
    noisy_result = result.apply_bitflips(probs)

    K.set_seed(123)
    if isinstance(probs, dict):
        probs = np.array([probs[q] for q in qubits])
    sprobs = K.to_numpy(K.random_uniform(samples.shape))
    target_samples = (samples + (sprobs < probs)) % 2
    K.assert_allclose(noisy_result.samples(), target_samples)
Example #3
0
def test_measurementresult_apply_bitflips_random_samples_asymmetric(backend):
    qubits = tuple(range(4))
    samples = np.random.randint(0, 2, (20, 4))
    result = measurements.MeasurementResult(qubits)
    result.binary = K.cast(np.copy(samples))
    p1_map = {0: 0.2, 1: 0.0, 2: 0.0, 3: 0.1}
    K.set_seed(123)
    noisy_result = result.apply_bitflips(p0=0.2, p1=p1_map)

    p0 = 0.2 * np.ones(4)
    p1 = np.array([0.2, 0.0, 0.0, 0.1])
    K.set_seed(123)
    sprobs = K.to_numpy(K.random_uniform(samples.shape))
    target_samples = np.copy(samples).ravel()
    ids = (np.where(target_samples == 0)[0], np.where(target_samples == 1)[0])
    target_samples[ids[0]] = samples.ravel()[ids[0]] + (sprobs < p0).ravel()[ids[0]]
    target_samples[ids[1]] = samples.ravel()[ids[1]] - (sprobs < p1).ravel()[ids[1]]
    target_samples = target_samples.reshape(samples.shape)
    K.assert_allclose(noisy_result.samples(), target_samples)
Example #4
0
    def apply_bitflips(self, p0: ProbsType, p1: Optional[ProbsType] = None):
        """Applies bitflip noise to the measured samples.

        Args:
            p0: Bitflip probability map. Can be:
                A dictionary that maps each measured qubit to the probability
                that it is flipped, a list or tuple that has the same length
                as the tuple of measured qubits or a single float number.
                If a single float is given the same probability will be used
                for all qubits.
            p1: Probability of asymmetric bitflip. If ``p1`` is given, ``p0``
                will be used as the probability for 0->1 and ``p1`` as the
                probability for 1->0. If ``p1`` is ``None`` the same probability
                ``p0`` will be used for both bitflips.

        Returns:
            A new :class:`qibo.core.measurements.MeasurementResult` object that
            holds the noisy samples.
        """
        if p1 is None:
            probs = 2 * (M._get_bitflip_tuple(self.qubits, p0),)
        else:
            probs = (M._get_bitflip_tuple(self.qubits, p0),
                     M._get_bitflip_tuple(self.qubits, p1))

        # Calculate noisy samples
        noiseless_samples = self.samples()
        fprobs = K.cast(probs, dtype='DTYPE')
        sprobs = K.random_uniform(noiseless_samples.shape)
        flip0 = K.cast(sprobs < fprobs[0], dtype=noiseless_samples.dtype)
        flip1 = K.cast(sprobs < fprobs[1], dtype=noiseless_samples.dtype)
        noisy_samples = noiseless_samples + (1 - noiseless_samples) * flip0
        noisy_samples = noisy_samples - noiseless_samples * flip1
        noisy_result = self.__class__(self.qubits)
        noisy_result.binary = noisy_samples
        return noisy_result