qiskit-aer
qiskit-aer copied to clipboard
Aer stabilizer simulator measurement outcomes depend on whether other measurements are done concurrently for large circuits
Informations
- Qiskit Aer version: 0.12.2
- Python version: 3.9.6
-
Operating system:
- Name of the operating system: posix
- Name of the OS system: Darwin
- Version of the operating system: 22.5.0
What is the current behavior?
I have been using large Clifford circuits (65 qubits total, 33 data qubit register, 32 ancilla qubit register, and one 32 bit classical register). The circuits consist of hadamards, cnots, resets, and measurement. I have found some strange behaviour in the measurement statistics that I see when run with the Aer stabilizer simulator.
In particular, the statistics from a measurement of one ancilla qubit depend on whether other measurements are performed concurrently on other ancilla qubits. This should not be the case. I see some ancilla qubit measurements deterministally give a 0 outcome when other measurements are performed concurrently, and if the other measurements are removed from the circuit then a deterministic 1 outcome is seen. (The 0 outcomes is the one that I expect).
Steps to reproduce the problem
I have an example of a circuit that demonstrates this behaviour. The circuit is a large example, I when I look at smaller circuits this behaviour disappears, so this is the smallest example I have.
Here is a circuit when all ancilla are measured
And here is a plot of the outcomes seen for each ancilla measurement over 10000 counts:
counts_measure_all_ancilla.pdf
Now, here is the same circuit but with some measurements removed:
circ_do_not_measure_all_ancilla.pdf
And here is the plot of the outcomes for the second circuit, again over 10000 counts
counts_do_not_measure_all_ancilla.pdf
The code to produce this output is:
from qiskit import qasm3, Aer, transpile, ClassicalRegister
from qiskit import ClassicalRegister
import copy
from matplotlib import pyplot as plt
import numpy as np
circ = qasm3.loads("""OPENQASM 3;
include "stdgates.inc";
qubit[33] qreg_dat;
qubit[32] qreg_anc;
h qreg_anc[0];
h qreg_anc[4];
h qreg_anc[6];
h qreg_anc[10];
h qreg_anc[12];
h qreg_anc[16];
h qreg_anc[18];
h qreg_anc[22];
h qreg_anc[24];
h qreg_anc[28];
h qreg_anc[30];
h qreg_anc[31];
barrier qreg_dat[0], qreg_dat[1], qreg_dat[2], qreg_dat[3], qreg_dat[4], qreg_dat[5], qreg_dat[6], qreg_dat[7], qreg_dat[8], qreg_dat[9], qreg_dat[10], qreg_dat[11], qreg_dat[12], qreg_dat[13], qreg_dat[14], qreg_dat[15], qreg_dat[16], qreg_dat[17], qreg_dat[18], qreg_dat[19], qreg_dat[20], qreg_dat[21], qreg_dat[22], qreg_dat[23], qreg_dat[24], qreg_dat[25], qreg_dat[26], qreg_dat[27], qreg_dat[28], qreg_dat[29], qreg_dat[30], qreg_dat[31], qreg_dat[32], qreg_anc[0], qreg_anc[1], qreg_anc[2], qreg_anc[3], qreg_anc[4], qreg_anc[5], qreg_anc[6], qreg_anc[7], qreg_anc[8], qreg_anc[9], qreg_anc[10], qreg_anc[11], qreg_anc[12], qreg_anc[13], qreg_anc[14], qreg_anc[15], qreg_anc[16], qreg_anc[17], qreg_anc[18], qreg_anc[19], qreg_anc[20], qreg_anc[21], qreg_anc[22], qreg_anc[23], qreg_anc[24], qreg_anc[25], qreg_anc[26], qreg_anc[27], qreg_anc[28], qreg_anc[29], qreg_anc[30], qreg_anc[31];
cx qreg_dat[1], qreg_anc[1];
cx qreg_dat[3], qreg_anc[3];
cx qreg_dat[5], qreg_anc[5];
cx qreg_dat[7], qreg_anc[7];
cx qreg_dat[9], qreg_anc[9];
cx qreg_dat[11], qreg_anc[11];
cx qreg_dat[13], qreg_anc[13];
cx qreg_dat[15], qreg_anc[15];
cx qreg_dat[17], qreg_anc[17];
cx qreg_dat[19], qreg_anc[19];
cx qreg_dat[21], qreg_anc[21];
cx qreg_dat[23], qreg_anc[23];
cx qreg_dat[25], qreg_anc[25];
cx qreg_dat[27], qreg_anc[27];
cx qreg_dat[29], qreg_anc[29];
cx qreg_anc[0], qreg_dat[0];
cx qreg_anc[4], qreg_dat[4];
cx qreg_anc[6], qreg_dat[6];
cx qreg_anc[10], qreg_dat[10];
cx qreg_anc[12], qreg_dat[12];
cx qreg_anc[16], qreg_dat[16];
cx qreg_anc[18], qreg_dat[18];
cx qreg_anc[22], qreg_dat[22];
cx qreg_anc[24], qreg_dat[24];
cx qreg_anc[28], qreg_dat[28];
cx qreg_anc[30], qreg_dat[30];
barrier qreg_dat[0], qreg_dat[1], qreg_dat[2], qreg_dat[3], qreg_dat[4], qreg_dat[5], qreg_dat[6], qreg_dat[7], qreg_dat[8], qreg_dat[9], qreg_dat[10], qreg_dat[11], qreg_dat[12], qreg_dat[13], qreg_dat[14], qreg_dat[15], qreg_dat[16], qreg_dat[17], qreg_dat[18], qreg_dat[19], qreg_dat[20], qreg_dat[21], qreg_dat[22], qreg_dat[23], qreg_dat[24], qreg_dat[25], qreg_dat[26], qreg_dat[27], qreg_dat[28], qreg_dat[29], qreg_dat[30], qreg_dat[31], qreg_dat[32], qreg_anc[0], qreg_anc[1], qreg_anc[2], qreg_anc[3], qreg_anc[4], qreg_anc[5], qreg_anc[6], qreg_anc[7], qreg_anc[8], qreg_anc[9], qreg_anc[10], qreg_anc[11], qreg_anc[12], qreg_anc[13], qreg_anc[14], qreg_anc[15], qreg_anc[16], qreg_anc[17], qreg_anc[18], qreg_anc[19], qreg_anc[20], qreg_anc[21], qreg_anc[22], qreg_anc[23], qreg_anc[24], qreg_anc[25], qreg_anc[26], qreg_anc[27], qreg_anc[28], qreg_anc[29], qreg_anc[30], qreg_anc[31];
cx qreg_dat[4], qreg_anc[1];
cx qreg_dat[6], qreg_anc[3];
cx qreg_dat[8], qreg_anc[5];
cx qreg_dat[10], qreg_anc[7];
cx qreg_dat[12], qreg_anc[9];
cx qreg_dat[14], qreg_anc[11];
cx qreg_dat[16], qreg_anc[13];
cx qreg_dat[18], qreg_anc[15];
cx qreg_dat[20], qreg_anc[17];
cx qreg_dat[22], qreg_anc[19];
cx qreg_dat[24], qreg_anc[21];
cx qreg_dat[26], qreg_anc[23];
cx qreg_dat[28], qreg_anc[25];
cx qreg_dat[30], qreg_anc[27];
cx qreg_dat[32], qreg_anc[29];
cx qreg_anc[0], qreg_dat[1];
cx qreg_anc[4], qreg_dat[5];
cx qreg_anc[6], qreg_dat[7];
cx qreg_anc[10], qreg_dat[11];
cx qreg_anc[12], qreg_dat[13];
cx qreg_anc[16], qreg_dat[17];
cx qreg_anc[18], qreg_dat[19];
cx qreg_anc[22], qreg_dat[23];
cx qreg_anc[24], qreg_dat[25];
cx qreg_anc[28], qreg_dat[29];
cx qreg_anc[30], qreg_dat[31];
barrier qreg_dat[0], qreg_dat[1], qreg_dat[2], qreg_dat[3], qreg_dat[4], qreg_dat[5], qreg_dat[6], qreg_dat[7], qreg_dat[8], qreg_dat[9], qreg_dat[10], qreg_dat[11], qreg_dat[12], qreg_dat[13], qreg_dat[14], qreg_dat[15], qreg_dat[16], qreg_dat[17], qreg_dat[18], qreg_dat[19], qreg_dat[20], qreg_dat[21], qreg_dat[22], qreg_dat[23], qreg_dat[24], qreg_dat[25], qreg_dat[26], qreg_dat[27], qreg_dat[28], qreg_dat[29], qreg_dat[30], qreg_dat[31], qreg_dat[32], qreg_anc[0], qreg_anc[1], qreg_anc[2], qreg_anc[3], qreg_anc[4], qreg_anc[5], qreg_anc[6], qreg_anc[7], qreg_anc[8], qreg_anc[9], qreg_anc[10], qreg_anc[11], qreg_anc[12], qreg_anc[13], qreg_anc[14], qreg_anc[15], qreg_anc[16], qreg_anc[17], qreg_anc[18], qreg_anc[19], qreg_anc[20], qreg_anc[21], qreg_anc[22], qreg_anc[23], qreg_anc[24], qreg_anc[25], qreg_anc[26], qreg_anc[27], qreg_anc[28], qreg_anc[29], qreg_anc[30], qreg_anc[31];
cx qreg_dat[3], qreg_anc[0];
cx qreg_dat[5], qreg_anc[2];
cx qreg_dat[7], qreg_anc[4];
cx qreg_dat[9], qreg_anc[6];
cx qreg_dat[11], qreg_anc[8];
cx qreg_dat[13], qreg_anc[10];
cx qreg_dat[15], qreg_anc[12];
cx qreg_dat[17], qreg_anc[14];
cx qreg_dat[19], qreg_anc[16];
cx qreg_dat[21], qreg_anc[18];
cx qreg_dat[23], qreg_anc[20];
cx qreg_dat[25], qreg_anc[22];
cx qreg_dat[27], qreg_anc[24];
cx qreg_dat[29], qreg_anc[26];
cx qreg_dat[31], qreg_anc[28];
cx qreg_anc[1], qreg_dat[2];
cx qreg_anc[3], qreg_dat[4];
cx qreg_anc[7], qreg_dat[8];
cx qreg_anc[9], qreg_dat[10];
cx qreg_anc[13], qreg_dat[14];
cx qreg_anc[15], qreg_dat[16];
cx qreg_anc[19], qreg_dat[20];
cx qreg_anc[21], qreg_dat[22];
cx qreg_anc[25], qreg_dat[26];
cx qreg_anc[27], qreg_dat[28];
cx qreg_anc[31], qreg_dat[32];
barrier qreg_dat[0], qreg_dat[1], qreg_dat[2], qreg_dat[3], qreg_dat[4], qreg_dat[5], qreg_dat[6], qreg_dat[7], qreg_dat[8], qreg_dat[9], qreg_dat[10], qreg_dat[11], qreg_dat[12], qreg_dat[13], qreg_dat[14], qreg_dat[15], qreg_dat[16], qreg_dat[17], qreg_dat[18], qreg_dat[19], qreg_dat[20], qreg_dat[21], qreg_dat[22], qreg_dat[23], qreg_dat[24], qreg_dat[25], qreg_dat[26], qreg_dat[27], qreg_dat[28], qreg_dat[29], qreg_dat[30], qreg_dat[31], qreg_dat[32], qreg_anc[0], qreg_anc[1], qreg_anc[2], qreg_anc[3], qreg_anc[4], qreg_anc[5], qreg_anc[6], qreg_anc[7], qreg_anc[8], qreg_anc[9], qreg_anc[10], qreg_anc[11], qreg_anc[12], qreg_anc[13], qreg_anc[14], qreg_anc[15], qreg_anc[16], qreg_anc[17], qreg_anc[18], qreg_anc[19], qreg_anc[20], qreg_anc[21], qreg_anc[22], qreg_anc[23], qreg_anc[24], qreg_anc[25], qreg_anc[26], qreg_anc[27], qreg_anc[28], qreg_anc[29], qreg_anc[30], qreg_anc[31];
cx qreg_dat[0], qreg_anc[0];
cx qreg_dat[2], qreg_anc[2];
cx qreg_dat[4], qreg_anc[4];
cx qreg_dat[6], qreg_anc[6];
cx qreg_dat[8], qreg_anc[8];
cx qreg_dat[10], qreg_anc[10];
cx qreg_dat[12], qreg_anc[12];
cx qreg_dat[14], qreg_anc[14];
cx qreg_dat[16], qreg_anc[16];
cx qreg_dat[18], qreg_anc[18];
cx qreg_dat[20], qreg_anc[20];
cx qreg_dat[22], qreg_anc[22];
cx qreg_dat[24], qreg_anc[24];
cx qreg_dat[26], qreg_anc[26];
cx qreg_dat[28], qreg_anc[28];
cx qreg_anc[1], qreg_dat[1];
cx qreg_anc[3], qreg_dat[3];
cx qreg_anc[7], qreg_dat[7];
cx qreg_anc[9], qreg_dat[9];
cx qreg_anc[13], qreg_dat[13];
cx qreg_anc[15], qreg_dat[15];
cx qreg_anc[19], qreg_dat[19];
cx qreg_anc[21], qreg_dat[21];
cx qreg_anc[25], qreg_dat[25];
cx qreg_anc[27], qreg_dat[27];
cx qreg_anc[31], qreg_dat[31];
barrier qreg_dat[0], qreg_dat[1], qreg_dat[2], qreg_dat[3], qreg_dat[4], qreg_dat[5], qreg_dat[6], qreg_dat[7], qreg_dat[8], qreg_dat[9], qreg_dat[10], qreg_dat[11], qreg_dat[12], qreg_dat[13], qreg_dat[14], qreg_dat[15], qreg_dat[16], qreg_dat[17], qreg_dat[18], qreg_dat[19], qreg_dat[20], qreg_dat[21], qreg_dat[22], qreg_dat[23], qreg_dat[24], qreg_dat[25], qreg_dat[26], qreg_dat[27], qreg_dat[28], qreg_dat[29], qreg_dat[30], qreg_dat[31], qreg_dat[32], qreg_anc[0], qreg_anc[1], qreg_anc[2], qreg_anc[3], qreg_anc[4], qreg_anc[5], qreg_anc[6], qreg_anc[7], qreg_anc[8], qreg_anc[9], qreg_anc[10], qreg_anc[11], qreg_anc[12], qreg_anc[13], qreg_anc[14], qreg_anc[15], qreg_anc[16], qreg_anc[17], qreg_anc[18], qreg_anc[19], qreg_anc[20], qreg_anc[21], qreg_anc[22], qreg_anc[23], qreg_anc[24], qreg_anc[25], qreg_anc[26], qreg_anc[27], qreg_anc[28], qreg_anc[29], qreg_anc[30], qreg_anc[31];
""")
# add all measurements
circ_all_meas = copy.deepcopy(circ)
qreg_anc = circ_all_meas.qregs[1]
creg = ClassicalRegister(32)
circ_all_meas.add_register(creg)
for i in range(32):
circ_all_meas.measure(qreg_anc[i], creg[i])
fig, ax = plt.subplots()
circ_all_meas.draw("mpl", scale = 0.6, fold = -1, ax=ax )
fig.savefig("circ_measure_all_ancilla.pdf")
sim = Aer.get_backend("aer_simulator_stabilizer")
circ_all_meas = transpile(circ_all_meas, sim)
result = sim.run(circ_all_meas, shots=10000).result()
counts = result.get_counts()
n_anc = 32
totals = np.zeros(n_anc, dtype=int)
for outcomes, num_counts in counts.items():
new_totals = num_counts * np.array([int(bit) for bit in outcomes][::-1])
assert len(new_totals) == n_anc # double check qiskit returns outcomes for bits with no attached measurements
totals += new_totals # reverse for list indexing
fig, ax = plt.subplots()
xs = np.arange(len(totals))
ax.bar(xs, totals)
ax.plot(xs, totals, linestyle='', marker='.') # so that deterministically zero outcomes can be seen
ax.set_xlabel("Ancilla qubit index")
ax.set_ylabel("Counts of 1")
ax.set_title("Measure all ancilla")
fig.savefig("counts_measure_all_ancilla.pdf")
# do not measure some
circ_some_meas = copy.deepcopy(circ)
qreg_anc = circ_some_meas.qregs[1]
creg = ClassicalRegister(32)
circ_some_meas.add_register(creg)
do_not_measure = [1, 3, 7]
for i in range(32):
if i not in do_not_measure:
circ_some_meas.measure(qreg_anc[i], creg[i])
fig, ax = plt.subplots()
circ_some_meas.draw("mpl", scale = 0.6, fold = -1 , ax=ax)
fig.savefig("circ_do_not_measure_all_ancilla.pdf")
sim = Aer.get_backend("aer_simulator_stabilizer")
circ_some_meas = transpile(circ_some_meas, sim)
result = sim.run(circ_some_meas, shots=10000).result()
counts = result.get_counts()
n_anc = 32
totals = np.zeros(n_anc, dtype=int)
for outcomes, num_counts in counts.items():
new_totals = num_counts * np.array([int(bit) for bit in outcomes][::-1])
assert len(new_totals) == n_anc # double check qiskit returns outcomes for bits with no attached measurements
totals += new_totals # reverse for list indexing
fig, ax = plt.subplots()
xs = np.arange(len(totals))
ax.bar(xs, totals)
ax.plot(xs, totals, linestyle='', marker='.') # so that deterministically zero outcomes can be seen
ax.set_title("Do not measure all ancilla")
ax.set_xlabel("Ancilla qubit index")
ax.set_ylabel("Counts of 1")
fig.savefig("counts_do_not_measure_all_ancilla.pdf")
What is the expected behavior?
The expected behavior is that measurement statistics of a qubit should not depend on whether other measurements were performed on a different qubit concurrently.
Suggested solutions
I don't know what is causing this problem, the only suggestion that I have is that it only appears when I looked at larger code instances.
I found issue in measurement code in stabilizer simulator. I'm now fixing it
ah ah, what is your meaning of statistics @sam-craig-smith? results outcome of statistics must depend the variants of input params
By statistics I mean what percentage of the time you see +1 outcomes compared to 0 outcomes. In the case of this circuit, each measurement outcome is either 0 all the time, or 0 with 50% probability and 1 with 50% probability, or 1 all the time.
The actual statistics seen depends on the circuit of course, but regardless of the circuit it shouldn't be the case that the statistics of measurement outcomes on one qubit depends on whether another measurement on another qubit was done concurrently.