Skip to content

Commit f566b83

Browse files
authored
Fix stim.Circuit.flow_generators inverting measurement index order within MPP instructions (#956)
1 parent 751dcf8 commit f566b83

File tree

4 files changed

+101
-1
lines changed

4 files changed

+101
-1
lines changed

src/stim/util_top/circuit_flow_generators.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ struct CircuitFlowGeneratorSolver {
3636
std::vector<size_t> buf_for_rows_with;
3737
std::vector<int32_t> buf_for_xor_merge;
3838
std::vector<GateTarget> buf_targets;
39+
std::vector<GateTarget> buf_targets_2;
3940

4041
explicit CircuitFlowGeneratorSolver(CircuitStats stats);
4142
static CircuitFlowGeneratorSolver<W> solver_with_circuit_generators(

src/stim/util_top/circuit_flow_generators.inl

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -364,7 +364,12 @@ void CircuitFlowGeneratorSolver<W>::undo_instruction(CircuitInstruction inst) {
364364
CircuitInstruction{inst.gate_type, {}, buf_targets, inst.tag},
365365
num_qubits,
366366
[&](CircuitInstruction sub_inst) {
367-
undo_instruction(sub_inst);
367+
buf_targets_2.clear();
368+
buf_targets_2.insert(buf_targets_2.end(), sub_inst.targets.begin(), sub_inst.targets.end());
369+
if (sub_inst.gate_type == GateType::M) {
370+
std::reverse(buf_targets_2.begin(), buf_targets_2.end());
371+
}
372+
undo_instruction(CircuitInstruction{sub_inst.gate_type, sub_inst.args, buf_targets_2, sub_inst.tag});
368373
});
369374
break;
370375

src/stim/util_top/circuit_flow_generators.test.cc

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,21 @@ TEST_EACH_WORD_SIZE_W(circuit_flow_generators, various, {
253253
Flow<W>::from_str("XXX -> _ZY xor rec[2]"),
254254
Flow<W>::from_str("Z_X -> _ZX xor rec[3]"),
255255
}));
256+
257+
EXPECT_EQ(
258+
circuit_flow_generators<W>(Circuit(R"CIRCUIT(
259+
MPP Y0*Y1 Y2*Y3
260+
)CIRCUIT")),
261+
(std::vector<Flow<W>>{
262+
Flow<W>::from_str("1 -> __YY xor rec[1]"),
263+
Flow<W>::from_str("1 -> YY__ xor rec[0]"),
264+
Flow<W>::from_str("___Y -> ___Y"),
265+
Flow<W>::from_str("__XZ -> __ZX xor rec[1]"),
266+
Flow<W>::from_str("__ZZ -> __ZZ"),
267+
Flow<W>::from_str("_Y__ -> _Y__"),
268+
Flow<W>::from_str("XZ__ -> ZX__ xor rec[0]"),
269+
Flow<W>::from_str("ZZ__ -> ZZ__"),
270+
}));
256271
})
257272

258273
TEST_EACH_WORD_SIZE_W(circuit_flow_generators, all_operations, {

src/stim/util_top/circuit_flow_generators_test.py

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,85 @@ def test_solve_flow_measurements():
2626
]) == [[0], [], [0]]
2727

2828

29+
def test_solve_flow_generators_measurements_multi_target():
30+
assert stim.Circuit("""
31+
M 1 2
32+
""").flow_generators() == [
33+
stim.Flow("1 -> __Z xor rec[1]"),
34+
stim.Flow("1 -> _Z_ xor rec[0]"),
35+
stim.Flow("__Z -> rec[1]"),
36+
stim.Flow("_Z_ -> rec[0]"),
37+
stim.Flow("X__ -> X__"),
38+
stim.Flow("Z__ -> Z__"),
39+
]
40+
41+
assert stim.Circuit("""
42+
MX 1 2
43+
""").flow_generators() == [
44+
stim.Flow("1 -> __X xor rec[1]"),
45+
stim.Flow("1 -> _X_ xor rec[0]"),
46+
stim.Flow("__X -> rec[1]"),
47+
stim.Flow("_X_ -> rec[0]"),
48+
stim.Flow("X__ -> X__"),
49+
stim.Flow("Z__ -> Z__"),
50+
]
51+
52+
assert stim.Circuit("""
53+
MYY 1 2 3 4
54+
""").flow_generators() == [
55+
stim.Flow("1 -> ___YY xor rec[1]"),
56+
stim.Flow("1 -> _YY__ xor rec[0]"),
57+
stim.Flow("____Y -> ____Y"),
58+
stim.Flow("___XZ -> ___ZX xor rec[1]"),
59+
stim.Flow("___ZZ -> ___ZZ"),
60+
stim.Flow("__Y__ -> __Y__"),
61+
stim.Flow("_XZ__ -> _ZX__ xor rec[0]"),
62+
stim.Flow("_ZZ__ -> _ZZ__"),
63+
stim.Flow("X____ -> X____"),
64+
stim.Flow("Z____ -> Z____"),
65+
]
66+
assert stim.Circuit("""
67+
MPP Y1*Y2 Y3*Y4
68+
""").flow_generators() == [
69+
stim.Flow("1 -> ___YY xor rec[1]"),
70+
stim.Flow("1 -> _YY__ xor rec[0]"),
71+
stim.Flow("____Y -> ____Y"),
72+
stim.Flow("___XZ -> ___ZX xor rec[1]"),
73+
stim.Flow("___ZZ -> ___ZZ"),
74+
stim.Flow("__Y__ -> __Y__"),
75+
stim.Flow("_XZ__ -> _ZX__ xor rec[0]"),
76+
stim.Flow("_ZZ__ -> _ZZ__"),
77+
stim.Flow("X____ -> X____"),
78+
stim.Flow("Z____ -> Z____"),
79+
]
80+
81+
82+
def test_solve_flow_measurements_multi_target():
83+
assert stim.Circuit("""
84+
M 1 2
85+
""").solve_flow_measurements([
86+
stim.Flow("Z1 -> 1"),
87+
]) == [[0]]
88+
89+
assert stim.Circuit("""
90+
MX 1 2
91+
""").solve_flow_measurements([
92+
stim.Flow("X1 -> 1"),
93+
]) == [[0]]
94+
95+
assert stim.Circuit("""
96+
MYY 1 2 3 4
97+
""").solve_flow_measurements([
98+
stim.Flow("Y1*Y2 -> 1"),
99+
]) == [[0]]
100+
101+
assert stim.Circuit("""
102+
MPP Y1*Y2 Y3*Y4
103+
""").solve_flow_measurements([
104+
stim.Flow("Y1*Y2 -> 1"),
105+
]) == [[0]]
106+
107+
29108
def test_solve_flow_measurements_fewer_measurements_heuristic():
30109
assert stim.Circuit("""
31110
MPP Z0*Z1*Z2*Z3*Z4*Z5*Z6*Z7*Z8

0 commit comments

Comments
 (0)