Describe the issue
cirq.defer_measurements does not preserve the record index of a BitMaskKeyCondition. When a measurement key is reused, a condition referring to an earlier record can become an unconditional operation after deferral, changing the measurement result.
The index should be preserved, or unsupported conditions should be rejected explicitly.
Explain how to reproduce the bug or problem
from collections import Counter
import cirq
q0, q1, q2 = cirq.LineQubit.range(3)
condition = cirq.BitMaskKeyCondition(
cirq.MeasurementKey("a"), index=0, target_value=0, equal_target=True
)
circuit = cirq.Circuit(
cirq.X(q0),
cirq.measure(q0, key="a"), # First record: 1.
cirq.measure(q1, key="a"), # Second record: 0.
cirq.X(q2).with_classical_controls(condition),
cirq.measure(q2, key="out"),
)
simulator = cirq.Simulator()
for label, candidate in [
("original", circuit),
("deferred", cirq.defer_measurements(circuit)),
]:
result = simulator.run(candidate, repetitions=1000)
print(label, Counter(result.records["out"].flatten().tolist()))
Observed output:
original Counter({0: 1000})
deferred Counter({1: 1000})
The condition tests whether the first record is zero, which is false. Both circuits should therefore measure out = 0 on every shot.
Tell us the version of Cirq where this happens
Cirq 1.7.0, Python 3.11.4, Linux.
Root cause
In measurement_transformers.py, defer_measurements preserves condition.index only for KeyCondition; BitMaskKeyCondition falls through to index -1. It therefore enumerates the latest record while the original condition still reads record 0, which is zero-filled in the synthetic datastore. In this example, the condition becomes true for every enumerated value.
Unlike #8360, where KeyCondition._qasm_ ignores the index during QASM export, this is a separate type-dispatch omission in the deferred-measurement transformer. No QASM conversion is involved, and deferral correctly preserves index=0 for KeyCondition in the corresponding test.
Describe the issue
cirq.defer_measurementsdoes not preserve the record index of aBitMaskKeyCondition. When a measurement key is reused, a condition referring to an earlier record can become an unconditional operation after deferral, changing the measurement result.The index should be preserved, or unsupported conditions should be rejected explicitly.
Explain how to reproduce the bug or problem
Observed output:
The condition tests whether the first record is zero, which is false. Both circuits should therefore measure
out = 0on every shot.Tell us the version of Cirq where this happens
Cirq 1.7.0, Python 3.11.4, Linux.
Root cause
In
measurement_transformers.py,defer_measurementspreservescondition.indexonly forKeyCondition;BitMaskKeyConditionfalls through to index-1. It therefore enumerates the latest record while the original condition still reads record0, which is zero-filled in the synthetic datastore. In this example, the condition becomes true for every enumerated value.Unlike #8360, where
KeyCondition._qasm_ignores the index during QASM export, this is a separate type-dispatch omission in the deferred-measurement transformer. No QASM conversion is involved, and deferral correctly preservesindex=0forKeyConditionin the corresponding test.