Skip to content
12 changes: 11 additions & 1 deletion cirq-core/cirq/transformers/align.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,4 +73,14 @@ def align_right(
"""
if context is not None and context.deep is True:
context = dataclasses.replace(context, deep=False)
return align_left(circuit[::-1], context=context)[::-1]
# Reverse the circuit, align left, and reverse again. Note each moment also has to have its ops
# reversed internally, to avoid edge conditions where non-commuting but can-be-in-same-moment
# ops (measurements and classical controls, particularly) could end up getting swapped.
backwards = []
for moment in circuit[::-1]:
backwards.append(circuits.Moment(reversed(moment.operations)))
aligned_backwards = align_left(circuits.Circuit(backwards), context=context)
forwards = []
for moment in aligned_backwards[::-1]:
forwards.append(circuits.Moment(reversed(moment.operations)))
return circuits.Circuit(forwards)
13 changes: 13 additions & 0 deletions cirq-core/cirq/transformers/align_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -208,3 +208,16 @@ def test_classical_control():
)
cirq.testing.assert_same_circuits(cirq.align_left(circuit), circuit)
cirq.testing.assert_same_circuits(cirq.align_right(circuit), circuit)


def test_measurement_and_classical_control_same_moment_preserve_order():
q0, q1 = cirq.LineQubit.range(2)
circuit = cirq.Circuit()
op_measure = cirq.measure(q0, key='m')
op_controlled = cirq.X(q1).with_classical_controls('m')
circuit.append(op_measure)
circuit.append(op_controlled, cirq.InsertStrategy.INLINE)
circuit = cirq.align_right(circuit)
ops_in_order = list(circuit.all_operations())
assert ops_in_order[0] == op_measure
assert ops_in_order[1] == op_controlled