def add_readout_error(
    measurements: np.ndarray,
    zero_errors: np.ndarray,
    one_errors: np.ndarray,
    rng: np.random.Generator,
) -> np.ndarray:
    """Add readout errors to measured (or simulated) bitstrings.

    Args:
        measurements: The bitstrings to which we will add readout errors. measurements[i,j] is the
                      ith bitstring, qubit j.
        zero_errors: zero_errors[i] is the probability of a 0->1 readout error on qubit i.
        one_errors: one_errors[i] is the probability of a 1->0 readout error on qubit i.
        rng: The pseudorandom number generator to use.

    Returns:
        New measurements but with readout errors added.
    """
    num_bitstrs, n = measurements.shape
    assert len(zero_errors) == len(one_errors) == n
    # compute the probability that each bit is 1 after adding readout errors:
    p1 = measurements * (1 - one_errors) + (1 - measurements) * zero_errors
    r = rng.random((num_bitstrs, n))
    noisy_measurements = r < p1
    return noisy_measurements.astype(int)
Add readout errors to measured (or simulated) bitstrings.

    Args:
        measurements: The bitstrings to which we will add readout errors. measurements[i,j] is the
                      ith bitstring, qubit j.
        zero_errors: zero_errors[i] is the probability of a 0->1 readout error on qubit i.
        one_errors: one_errors[i] is the probability of a 1->0 readout error on qubit i.
        rng: The pseudorandom number generator to use.

    Returns:
        New measurements but with readout errors added.
    
cirq-core/cirq/experiments/readout_confusion_matrix_test.py