From 24f978f81d0fa34269bb51595b2dd7045bc3541a Mon Sep 17 00:00:00 2001 From: Craig Gidney Date: Sun, 19 Nov 2023 15:40:04 -0800 Subject: [PATCH] Rename "m" to "rec" in qasm output Fix decomp check handling resets wrong --- src/stim/circuit/circuit.pybind.cc | 6 +- src/stim/circuit/export_qasm.cc | 10 +-- src/stim/circuit/export_qasm.test.cc | 114 +++++++++++++-------------- src/stim/circuit/gate_data.h | 2 +- src/stim/circuit/gate_data.test.cc | 17 +++- 5 files changed, 80 insertions(+), 69 deletions(-) diff --git a/src/stim/circuit/circuit.pybind.cc b/src/stim/circuit/circuit.pybind.cc index 43d28ded1..b2e2d8ff0 100644 --- a/src/stim/circuit/circuit.pybind.cc +++ b/src/stim/circuit/circuit.pybind.cc @@ -1432,14 +1432,14 @@ void stim_pybind::pybind_circuit_methods(pybind11::module &, pybind11::class_ m[0]; - measure q[1] -> m[1]; + measure q[0] -> rec[0]; + measure q[1] -> rec[1]; dets[0] = rec[1] ^ rec[0] ^ 0; )DOC") .data()); diff --git a/src/stim/circuit/export_qasm.cc b/src/stim/circuit/export_qasm.cc index 019fcda3c..2a7d6dce6 100644 --- a/src/stim/circuit/export_qasm.cc +++ b/src/stim/circuit/export_qasm.cc @@ -102,7 +102,7 @@ static void do_qasm_decompose_mpp( out << "cx q[" << t1.qubit_value() << "],q[" << t2.qubit_value() << "];"; } for (auto t : meas.targets) { - out << "measure q[" << t.qubit_value() << "] -> m[" << measurement_offset << "];"; + out << "measure q[" << t.qubit_value() << "] -> rec[" << measurement_offset << "];"; measurement_offset++; } for (size_t k = 0; k < cnot.targets.size(); k += 2) { @@ -141,7 +141,7 @@ static void qasm_output_decomposed_inline( q1 << "q[" << t1.qubit_value() << "]"; if (f & GATE_PRODUCES_RESULTS) { m.str(""); - m << "m[" << measurement_offset << "]"; + m << "rec[" << measurement_offset << "]"; measurement_offset++; } do_decomposed( @@ -149,7 +149,7 @@ static void qasm_output_decomposed_inline( out << " // decomposed " << GATE_DATA[instruction.gate_type].name << "\n"; } else { if (f & GATE_PRODUCES_RESULTS) { - out << "m[" << measurement_offset << "] = "; + out << "rec[" << measurement_offset << "] = "; measurement_offset++; } out << qasm_names[(int)instruction.gate_type] << "("; @@ -404,7 +404,7 @@ void stim::export_open_qasm(const Circuit &circuit, std::ostream &out, int open_ out << qubit_decl << " q[" << stats.num_qubits << "];\n"; } if (stats.num_measurements > 0) { - out << bit_decl << " m[" << stats.num_measurements << "];\n"; + out << bit_decl << " rec[" << stats.num_measurements << "];\n"; } if (stats.num_detectors > 0 && !skip_dets_and_obs) { out << bit_decl << " dets[" << stats.num_detectors << "];\n"; @@ -444,7 +444,7 @@ void stim::export_open_qasm(const Circuit &circuit, std::ostream &out, int open_ case GateType::M: for (const auto &t : instruction.targets) { - out << "measure q[" << t.qubit_value() << "] -> m[" << measurement_offset << "];\n"; + out << "measure q[" << t.qubit_value() << "] -> rec[" << measurement_offset << "];\n"; measurement_offset++; } return; diff --git a/src/stim/circuit/export_qasm.test.cc b/src/stim/circuit/export_qasm.test.cc index 07b25b004..c77d364db 100644 --- a/src/stim/circuit/export_qasm.test.cc +++ b/src/stim/circuit/export_qasm.test.cc @@ -26,13 +26,13 @@ include "stdgates.inc"; gate cxyz q0 { U(pi/2, 0, pi/2) q0; } qubit q[2]; -bit m[1]; +bit rec[1]; bit sweep[6]; h q[0]; cx q[0], q[1]; cxyz q[1]; -measure q[0] -> m[0]; +measure q[0] -> rec[0]; if (ms[0]) { X q[1]; } @@ -77,7 +77,7 @@ TEST(export_circuit, export_open_qasm_qec) { include "stdgates.inc"; qubit q[3]; -bit m[4]; +bit rec[4]; bit dets[3]; bit obs[1]; @@ -95,7 +95,7 @@ barrier q; cx q[2], q[1]; barrier q; -measure q[1] -> m[0]; +measure q[1] -> rec[0]; dets[0] = rec[0] ^ 1; barrier q; @@ -108,9 +108,9 @@ barrier q; cx q[2], q[1]; barrier q; -measure q[0] -> m[1]; -measure q[1] -> m[2]; -measure q[2] -> m[3]; +measure q[0] -> rec[1]; +measure q[1] -> rec[2]; +measure q[2] -> rec[3]; dets[1] = rec[2] ^ rec[0] ^ 0; dets[2] = rec[3] ^ rec[2] ^ rec[1] ^ 0; obs[0] = obs[0] ^ rec[3] ^ 0; @@ -123,7 +123,7 @@ obs[0] = obs[0] ^ rec[3] ^ 0; include "qelib1.inc"; qreg q[3]; -creg m[4]; +creg rec[4]; reset q[0]; reset q[1]; @@ -139,7 +139,7 @@ barrier q; cx q[2], q[1]; barrier q; -measure q[1] -> m[0]; +measure q[1] -> rec[0]; barrier q; reset q[1]; @@ -151,9 +151,9 @@ barrier q; cx q[2], q[1]; barrier q; -measure q[0] -> m[1]; -measure q[1] -> m[2]; -measure q[2] -> m[3]; +measure q[0] -> rec[1]; +measure q[1] -> rec[2]; +measure q[2] -> rec[3]; )QASM"); } @@ -185,22 +185,22 @@ def rx(qubit q0) { reset q0; h q0; } def mxx(qubit q0, qubit q1) -> bit { bit b; cx q0, q1; h q0; measure q0 -> b; h q0; cx q0, q1; return b; } qubit q[5]; -bit m[5]; +bit rec[5]; bit dets[1]; reset q[3]; rx(q[0]); rx(q[1]); -m[0] = mx(q[2]); +rec[0] = mx(q[2]); barrier q; -m[1] = mxx(q[0], q[1]); +rec[1] = mxx(q[0], q[1]); dets[0] = rec[1] ^ 0; barrier q; -measure q[2] -> m[2]; -m[3] = mr(q[3]); -m[4] = mrx(q[4]); +measure q[2] -> rec[2]; +rec[3] = mr(q[3]); +rec[4] = mrx(q[4]); )QASM"); out.str(""); @@ -210,27 +210,26 @@ m[4] = mrx(q[4]); include "qelib1.inc"; qreg q[5]; -creg m[5]; +creg rec[5]; reset q[3]; reset q[0]; h q[0]; // decomposed RX reset q[1]; h q[1]; // decomposed RX -h q[2]; measure q[2] -> m[0]; h q[2]; // decomposed MX +h q[2]; measure q[2] -> rec[0]; h q[2]; // decomposed MX barrier q; -cx q[0], q[1]; h q[0]; measure q[0] -> m[1]; h q[0]; cx q[0], q[1]; // decomposed MXX +cx q[0], q[1]; h q[0]; measure q[0] -> rec[1]; h q[0]; cx q[0], q[1]; // decomposed MXX barrier q; -measure q[2] -> m[2]; -measure q[3] -> m[3]; reset q[3]; // decomposed MR -h q[4]; measure q[4] -> m[4]; reset q[4]; h q[4]; // decomposed MRX +measure q[2] -> rec[2]; +measure q[3] -> rec[3]; reset q[3]; // decomposed MR +h q[4]; measure q[4] -> rec[4]; reset q[4]; h q[4]; // decomposed MRX )QASM"); } TEST(export_circuit, export_qasm_all_operations) { Circuit c = generate_test_circuit_with_all_operations(); c = c.without_noise(); - c = circuit_with_inlined_feedback(c); std::stringstream out; export_open_qasm(c, out, 3, false); @@ -271,7 +270,7 @@ def myy(qubit q0, qubit q1) -> bit { bit b; s q0; s q1; cx q0, q1; h q0; measure def mzz(qubit q0, qubit q1) -> bit { bit b; cx q0, q1; measure q1 -> b; cx q0, q1; return b; } qubit q[18]; -bit m[20]; +bit rec[20]; bit dets[1]; bit obs[1]; @@ -318,24 +317,24 @@ barrier q; barrier q; -h q[0];sx q[1];cx q[1],q[0];cx q[2],q[0];measure q[0] -> m[2];cx q[1],q[0];cx q[2],q[0];sxdg q[1];h q[0]; // decomposed MPP -cx q[1],q[0];measure q[0] -> m[3];cx q[1],q[0]; // decomposed MPP -m[4] = mrx(q[0]); -m[5] = mry(q[1]); -m[6] = mr(q[2]); -m[7] = mx(q[3]); -m[8] = my(q[4]); -measure q[5] -> m[9]; -measure q[6] -> m[10]; +h q[0];sx q[1];cx q[1],q[0];cx q[2],q[0];measure q[0] -> rec[2];cx q[1],q[0];cx q[2],q[0];sxdg q[1];h q[0]; // decomposed MPP +cx q[1],q[0];measure q[0] -> rec[3];cx q[1],q[0]; // decomposed MPP +rec[4] = mrx(q[0]); +rec[5] = mry(q[1]); +rec[6] = mr(q[2]); +rec[7] = mx(q[3]); +rec[8] = my(q[4]); +measure q[5] -> rec[9]; +measure q[6] -> rec[10]; rx(q[7]); ry(q[8]); reset q[9]; barrier q; -m[11] = mxx(q[0], q[1]); -m[12] = mxx(q[2], q[3]); -m[13] = myy(q[4], q[5]); -m[14] = mzz(q[6], q[7]); +rec[11] = mxx(q[0], q[1]); +rec[12] = mxx(q[2], q[3]); +rec[13] = myy(q[4], q[5]); +rec[14] = mzz(q[6], q[7]); barrier q; h q[0]; @@ -355,8 +354,8 @@ barrier q; barrier q; -m[15] = mr(q[0]); -m[16] = mr(q[0]); +rec[15] = mr(q[0]); +rec[16] = mr(q[0]); dets[0] = rec[16] ^ 0; obs[0] = obs[0] ^ rec[16] ^ 0; barrier q; @@ -364,6 +363,7 @@ barrier q; )QASM"); out.str(""); + c = circuit_with_inlined_feedback(c); export_open_qasm(c, out, 2, true); ASSERT_EQ(out.str(), R"QASM(OPENQASM 2.0; @@ -392,7 +392,7 @@ gate swapcx q0, q1 { cx q0, q1; cx q1, q0; } gate iswapdg q0, q1 { s q0; s q0; s q0; s q1; s q1; s q1; h q1; cx q1, q0; cx q0, q1; h q0; } qreg q[18]; -creg m[20]; +creg rec[20]; id q[0]; x q[1]; @@ -437,24 +437,24 @@ barrier q; barrier q; -h q[0];sx q[1];cx q[1],q[0];cx q[2],q[0];measure q[0] -> m[2];cx q[1],q[0];cx q[2],q[0];sxdg q[1];h q[0]; // decomposed MPP -cx q[1],q[0];measure q[0] -> m[3];cx q[1],q[0]; // decomposed MPP -h q[0]; measure q[0] -> m[4]; reset q[0]; h q[0]; // decomposed MRX -s q[1]; s q[1]; s q[1]; h q[1]; measure q[1] -> m[5]; reset q[1]; h q[1]; s q[1]; // decomposed MRY -measure q[2] -> m[6]; reset q[2]; // decomposed MR -h q[3]; measure q[3] -> m[7]; h q[3]; // decomposed MX -s q[4]; s q[4]; s q[4]; h q[4]; measure q[4] -> m[8]; h q[4]; s q[4]; // decomposed MY -measure q[5] -> m[9]; -measure q[6] -> m[10]; +h q[0];sx q[1];cx q[1],q[0];cx q[2],q[0];measure q[0] -> rec[2];cx q[1],q[0];cx q[2],q[0];sxdg q[1];h q[0]; // decomposed MPP +cx q[1],q[0];measure q[0] -> rec[3];cx q[1],q[0]; // decomposed MPP +h q[0]; measure q[0] -> rec[4]; reset q[0]; h q[0]; // decomposed MRX +s q[1]; s q[1]; s q[1]; h q[1]; measure q[1] -> rec[5]; reset q[1]; h q[1]; s q[1]; // decomposed MRY +measure q[2] -> rec[6]; reset q[2]; // decomposed MR +h q[3]; measure q[3] -> rec[7]; h q[3]; // decomposed MX +s q[4]; s q[4]; s q[4]; h q[4]; measure q[4] -> rec[8]; h q[4]; s q[4]; // decomposed MY +measure q[5] -> rec[9]; +measure q[6] -> rec[10]; reset q[7]; h q[7]; // decomposed RX reset q[8]; h q[8]; s q[8]; // decomposed RY reset q[9]; barrier q; -cx q[0], q[1]; h q[0]; measure q[0] -> m[11]; h q[0]; cx q[0], q[1]; // decomposed MXX -cx q[2], q[3]; h q[2]; measure q[2] -> m[12]; h q[2]; cx q[2], q[3]; // decomposed MXX -s q[4]; s q[5]; cx q[4], q[5]; h q[4]; measure q[4] -> m[13]; s q[5]; s q[5]; h q[4]; cx q[4], q[5]; s q[4]; s q[5]; // decomposed MYY -cx q[6], q[7]; measure q[7] -> m[14]; cx q[6], q[7]; // decomposed MZZ +cx q[0], q[1]; h q[0]; measure q[0] -> rec[11]; h q[0]; cx q[0], q[1]; // decomposed MXX +cx q[2], q[3]; h q[2]; measure q[2] -> rec[12]; h q[2]; cx q[2], q[3]; // decomposed MXX +s q[4]; s q[5]; cx q[4], q[5]; h q[4]; measure q[4] -> rec[13]; s q[5]; s q[5]; h q[4]; cx q[4], q[5]; s q[4]; s q[5]; // decomposed MYY +cx q[6], q[7]; measure q[7] -> rec[14]; cx q[6], q[7]; // decomposed MZZ barrier q; h q[0]; @@ -474,8 +474,8 @@ barrier q; barrier q; -measure q[0] -> m[15]; reset q[0]; // decomposed MR -measure q[0] -> m[16]; reset q[0]; // decomposed MR +measure q[0] -> rec[15]; reset q[0]; // decomposed MR +measure q[0] -> rec[16]; reset q[0]; // decomposed MR barrier q; )QASM"); diff --git a/src/stim/circuit/gate_data.h b/src/stim/circuit/gate_data.h index 9b201ac46..721ddb32c 100644 --- a/src/stim/circuit/gate_data.h +++ b/src/stim/circuit/gate_data.h @@ -209,7 +209,7 @@ enum GateFlags : uint16_t { struct Gate { /// The canonical name of the gate, used when printing it to a circuit file. - const char *name = nullptr; + const char *name; /// The gate's type, such as stim::GateType::X or stim::GateType::MRZ. GateType id; /// The id of the gate inverse to this one, or at least the closest thing to an inverse. diff --git a/src/stim/circuit/gate_data.test.cc b/src/stim/circuit/gate_data.test.cc index b38034007..1e0fa2bc0 100644 --- a/src/stim/circuit/gate_data.test.cc +++ b/src/stim/circuit/gate_data.test.cc @@ -104,10 +104,19 @@ bool is_decomposition_correct(const Gate &gate) { Circuit circuit1 = epr; circuit1.safe_append_u(gate.name, qs); - auto v1 = circuit_output_eq_val(circuit1); - Circuit circuit2 = epr + Circuit(decomposition); - auto v2 = circuit_output_eq_val(circuit2); + + // Reset gates make the ancillary qubits irrelevant because the final value is unrelated to the initial value. + // So, for reset gates, discard the ancillary qubits. + // CAUTION: this could give false positives if "partial reset" gates are added in the future. + // (E.g. a two qubit gate that resets only one of the qubits.) + if ((gate.flags & GATE_IS_RESET) && !(gate.flags & GATE_PRODUCES_RESULTS)) { + for (auto q : qs) { + circuit1.safe_append_u("R", {q + 2}); + circuit2.safe_append_u("R", {q + 2}); + } + } + for (const auto &op : circuit2.operations) { if (op.gate_type != GateType::CX && op.gate_type != GateType::H && op.gate_type != GateType::S && op.gate_type != GateType::M && op.gate_type != GateType::R) { @@ -115,6 +124,8 @@ bool is_decomposition_correct(const Gate &gate) { } } + auto v1 = circuit_output_eq_val(circuit1); + auto v2 = circuit_output_eq_val(circuit2); return v1 == v2; }