I recently added a to_qasm
method to stim. An issue I'm having is how to test that the outputs are correct. I can test OpenQASM 2 outputs by giving the output to qiskit, which can parse OpenQASM 2 and execute the result. But it seems that qiskit doesn't support OpenQASM 3 features like classical operations (e.g. dets[5] = rec[1] ^ rec[2]
) and subroutines (e.g. def mx(qubit q0) -> bit { bit b; h q0; measure q0 -> b; h q0; return b; }
).
Here's an example of how I test OpenQASM 2 output:
def test_to_qasm2_runs_in_qiskit():
pytest.importorskip("qiskit")
pytest.importorskip("qiskit_aer")
import qiskit
import qiskit_aer
stim_circuit = stim.Circuit("""
R 0 1
MZZ !0 1
""")
qasm = stim_circuit.to_qasm(open_qasm_version=2)
# Verify it parses.
qiskit_circuit = qiskit.QuantumCircuit.from_qasm_str(qasm)
# Verify it implements the correct behavior.
counts = qiskit_aer.AerSimulator().run(qiskit_circuit, shots=8).result().get_counts(qiskit_circuit)
assert counts['1'] == 8
Is there something equivalent I can do to verify OpenQASM 3 code is correct? Are there tools out there that parse it? That simulate the parsed result?
Here's an example of the kind of thing I would test. This is a d=5 r=5 repetition code generated by stim, converted to qasm 3:
OPENQASM 3.0;
include "stdgates.inc";
def mr(qubit q0) -> bit { bit b; measure q0 -> b; reset q0; return b; }
qreg q[9];
creg rec[25];
creg dets[24];
creg obs[1];
reset q[0];
reset q[1];
reset q[2];
reset q[3];
reset q[4];
reset q[5];
reset q[6];
reset q[7];
reset q[8];
barrier q;
cx q[0], q[1];
cx q[2], q[3];
cx q[4], q[5];
cx q[6], q[7];
barrier q;
cx q[2], q[1];
cx q[4], q[3];
cx q[6], q[5];
cx q[8], q[7];
barrier q;
rec[0] = mr(q[1]);
rec[1] = mr(q[3]);
rec[2] = mr(q[5]);
rec[3] = mr(q[7]);
dets[0] = rec[0] ^ 0;
dets[1] = rec[1] ^ 0;
dets[2] = rec[2] ^ 0;
dets[3] = rec[3] ^ 0;
barrier q;
cx q[0], q[1];
cx q[2], q[3];
cx q[4], q[5];
cx q[6], q[7];
barrier q;
cx q[2], q[1];
cx q[4], q[3];
cx q[6], q[5];
cx q[8], q[7];
barrier q;
rec[4] = mr(q[1]);
rec[5] = mr(q[3]);
rec[6] = mr(q[5]);
rec[7] = mr(q[7]);
dets[4] = rec[4] ^ rec[0] ^ 0;
dets[5] = rec[5] ^ rec[1] ^ 0;
dets[6] = rec[6] ^ rec[2] ^ 0;
dets[7] = rec[7] ^ rec[3] ^ 0;
barrier q;
cx q[0], q[1];
cx q[2], q[3];
cx q[4], q[5];
cx q[6], q[7];
barrier q;
cx q[2], q[1];
cx q[4], q[3];
cx q[6], q[5];
cx q[8], q[7];
barrier q;
rec[8] = mr(q[1]);
rec[9] = mr(q[3]);
rec[10] = mr(q[5]);
rec[11] = mr(q[7]);
dets[8] = rec[8] ^ rec[4] ^ 0;
dets[9] = rec[9] ^ rec[5] ^ 0;
dets[10] = rec[10] ^ rec[6] ^ 0;
dets[11] = rec[11] ^ rec[7] ^ 0;
barrier q;
cx q[0], q[1];
cx q[2], q[3];
cx q[4], q[5];
cx q[6], q[7];
barrier q;
cx q[2], q[1];
cx q[4], q[3];
cx q[6], q[5];
cx q[8], q[7];
barrier q;
rec[12] = mr(q[1]);
rec[13] = mr(q[3]);
rec[14] = mr(q[5]);
rec[15] = mr(q[7]);
dets[12] = rec[12] ^ rec[8] ^ 0;
dets[13] = rec[13] ^ rec[9] ^ 0;
dets[14] = rec[14] ^ rec[10] ^ 0;
dets[15] = rec[15] ^ rec[11] ^ 0;
barrier q;
cx q[0], q[1];
cx q[2], q[3];
cx q[4], q[5];
cx q[6], q[7];
barrier q;
cx q[2], q[1];
cx q[4], q[3];
cx q[6], q[5];
cx q[8], q[7];
barrier q;
rec[16] = mr(q[1]);
rec[17] = mr(q[3]);
rec[18] = mr(q[5]);
rec[19] = mr(q[7]);
dets[16] = rec[16] ^ rec[12] ^ 0;
dets[17] = rec[17] ^ rec[13] ^ 0;
dets[18] = rec[18] ^ rec[14] ^ 0;
dets[19] = rec[19] ^ rec[15] ^ 0;
measure q[0] -> rec[20];
measure q[2] -> rec[21];
measure q[4] -> rec[22];
measure q[6] -> rec[23];
measure q[8] -> rec[24];
dets[20] = rec[21] ^ rec[20] ^ rec[16] ^ 0;
dets[21] = rec[22] ^ rec[21] ^ rec[17] ^ 0;
dets[22] = rec[23] ^ rec[22] ^ rec[18] ^ 0;
dets[23] = rec[24] ^ rec[23] ^ rec[19] ^ 0;
obs[0] = obs[0] ^ rec[24] ^ 0;