@@ -72,8 +72,11 @@ def test_get_detector_error_model_with_gauge_detectors():
7272 DETECTOR rec[-2]
7373 """
7474 )
75+ # Gauge errors that only trigger observables (error(0.5) L0) are removed,
76+ # but gauge errors that trigger detectors (error(0.5) D0) are kept.
7577 assert get_detector_error_model (c ).approx_equals (
76- stim .DetectorErrorModel ("error(0.01) D0 L0" ), atol = 1e-12
78+ stim .DetectorErrorModel ("error(0.5) D0\n error(0.01) D0 L0" ),
79+ atol = 1e-12 ,
7780 )
7881
7982
@@ -111,7 +114,6 @@ def test_get_detector_error_model_no_errors():
111114
112115
113116def test_get_detector_error_model_with_logical_observables ():
114-
115117 with pytest .raises (
116118 ValueError , match = "The number of observables changed after conversion."
117119 ):
@@ -125,3 +127,95 @@ def test_get_detector_error_model_with_logical_observables():
125127 """
126128 )
127129 get_detector_error_model (c )
130+
131+
132+ def test_get_detector_error_model_with_mpp_single_product ():
133+ """Test that a single MPP product is correctly counted as 1 measurement."""
134+ # MPP X0*X1*X2 measures a single Pauli product and produces exactly 1 measurement
135+ c = stim .Circuit (
136+ """
137+ R 0 1 2
138+ H 0 1 2
139+ X_ERROR(0.01) 0
140+ MPP X0*X1*X2
141+ OBSERVABLE_INCLUDE(0) rec[-1]
142+ M 0
143+ DETECTOR rec[-1] rec[-2]
144+ """
145+ )
146+ dem = get_detector_error_model (c )
147+ assert dem .num_detectors == 1
148+ assert dem .num_observables == 1
149+ assert "D0" in str (dem )
150+ assert "L0" in str (dem )
151+
152+
153+ def test_get_detector_error_model_with_mpp_multiple_products ():
154+ """Test that MPP with multiple products produces one measurement per product.
155+
156+ MPP X0*X1 Z2*Z3 Y4 produces 3 measurements (one per space-separated product).
157+ """
158+ c = stim .Circuit (
159+ """
160+ R 0 1 2 3 4
161+ H 0 1 2 3 4
162+ X_ERROR(0.01) 0
163+ MPP X0*X1 Z2*Z3 Y4
164+ OBSERVABLE_INCLUDE(0) rec[-3]
165+ M 0
166+ DETECTOR rec[-1] rec[-4]
167+ """
168+ )
169+ dem = get_detector_error_model (c )
170+ # rec[-3] refers to the first MPP product (X0*X1) since MPP produces 3 measurements
171+ # and then M produces 1, so rec[-4] is X0*X1, rec[-3] is Z2*Z3, rec[-2] is Y4, rec[-1] is M
172+ assert dem .num_detectors == 1
173+ assert dem .num_observables == 1
174+
175+
176+ def test_get_detector_error_model_with_multiple_mpp_instructions ():
177+ """Test multiple separate MPP instructions with OBSERVABLE_INCLUDE between them."""
178+ c = stim .Circuit (
179+ """
180+ R 0 1 2 3
181+ H 0 1 2 3
182+ X_ERROR(0.01) 0
183+ MPP X0*X1
184+ OBSERVABLE_INCLUDE(0) rec[-1]
185+ MPP X2*X3
186+ DETECTOR rec[-1] rec[-2]
187+ """
188+ )
189+ dem = get_detector_error_model (c )
190+ assert dem .num_detectors == 1
191+ assert dem .num_observables == 1
192+
193+
194+ def test_get_detector_error_model_mpp_measurement_counting ():
195+ """Test correct measurement counting for MPP vs regular M measurements.
196+
197+ This test verifies that rec indices are correctly adjusted when MPP instructions
198+ produce multiple measurements. The circuit has a non-deterministic observable
199+ (Z2*Z3 measured on |++⟩ state), which should raise a ValueError because stim
200+ interprets it as a gauge and eliminates it.
201+ """
202+ # Circuit with MPP producing 2 measurements + M producing 2 measurements
203+ c = stim .Circuit (
204+ """
205+ R 0 1 2 3
206+ H 0 1 2 3
207+ Z_ERROR(0.01) 0
208+ MPP Z0*Z1 Z2*Z3
209+ M 0 1
210+ OBSERVABLE_INCLUDE(0) rec[-3]
211+ DETECTOR rec[-4] rec[-2] rec[-1]
212+ """
213+ )
214+ # MPP Z0*Z1 Z2*Z3 produces 2 measurements: rec[-4] and rec[-3] (before M)
215+ # M 0 1 produces 2 measurements: rec[-2] and rec[-1]
216+ # OBSERVABLE_INCLUDE(0) rec[-3] refers to the Z2*Z3 measurement
217+ # Since the observable is non-deterministic (gauge), it gets eliminated
218+ with pytest .raises (
219+ ValueError , match = "The number of observables changed after conversion."
220+ ):
221+ get_detector_error_model (c )
0 commit comments