-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Add drop_diagonal_before_measurement transformer #7790
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Add drop_diagonal_before_measurement transformer #7790
Conversation
This transformer removes diagonal gates (Z, CZ, etc.) that appear immediately before measurements, as they do not affect the measurement outcome in the computational basis. Uses eject_z to maximize optimization opportunities. Fixes quantumlib#4935
|
Discussed in Cirq Cynq: there is concern about whether this is valid for all types of measurements, or only valid for terminal measurements. |
|
Theoretical Justification & Safety Against Phase Kickback To address the discussion regarding phase effects and safety, here is the theoretical basis for this optimization and how the implementation explicitly handles the "phase preservation" concerns.
Because they commute, the probability distribution of the measurement outcomes is invariant under the application of D: (Since D is unitary, D†D=I).
if all(q in measured_qubits for q in op.qubits):
# Only remove if ALL entangled partners are being measured.
Summary: The transformer is safe because it only removes diagonal gates when all their logical influence (phase) flows into a measurement that discards it, preventing any corruption of unmeasured wires via entanglement. |
|
Following up on the discussion in the sync meeting, with the condition that all qubits acted on by the gate are measured, it seems to me ok to remove the gate mid-circuit. My proof is like this: if there are So in the end the gate + measurement only changes global phase. About the implementation, I am concerned that |
|
@codrut3 thanks for your review , i will make changes . |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #7790 +/- ##
========================================
Coverage 99.57% 99.57%
========================================
Files 1102 1104 +2
Lines 98638 98876 +238
========================================
+ Hits 98218 98455 +237
- Misses 420 421 +1 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
| from cirq.transformers.eject_z import eject_z | ||
|
|
||
|
|
||
| def _is_diagonal(op: cirq.Operation) -> bool: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps _is_z_or_cz_pow_gate is a better name because it conveys better what it checks.
| After `eject_z`, the Z gate on the control qubit commutes through the CZ: | ||
|
|
||
| CZ(q0, q1) - Z(q1) - measure(q1) | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The docstring should be updated to reflect the code. A diagonal gate is dropped only if all its qubits are measured. So the CZ(q0, q1) - Z(q1) - measure(q1) example is not correct, because the CZ gate can't be removed. If q0 is also measured then it can be removed.
| ... ) | ||
| >>> optimized = cirq.drop_diagonal_before_measurement(circuit) | ||
| >>> print(optimized) | ||
| 1: ───M─── |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should still include the CZ gate.
| if protocols.is_measurement(op): | ||
| measured_qubits.update(op.qubits) | ||
| new_ops.append(op) | ||
| # If this is a diagonal gate and ANY of its qubits will be measured, remove it |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ALL
|
|
||
| new_ops.append(op) | ||
| # Note: We do NOT remove qubits from measured_qubits here. | ||
| # Diagonal gates commute with other diagonal gates. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add a test for this? A CZ gate followed by a diagonal 4x4 unitary followed by measurement on both qubits.
| This is because: | ||
| 1. Z on the control qubit of CZ commutes through the CZ | ||
| 2. After commutation, both gates are diagonal and before measurement | ||
| 3. Both can be removed |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Update the docstring: the CZ gate can't be removed if only q1 is measured
| ) -> cirq.Circuit: | ||
| """Removes diagonal gates that appear immediately before measurements. | ||
|
|
||
| This transformer optimizes circuits by removing diagonal gates (gates that are |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Clarify that only Z, CZ and their powers are removed.
|
Thank you for this PR, @Vivek1106-04 ! I left some comments, but someone from the Cirq team needs to review. @pavoljuhas maybe you can have a look? |
|
"Done! I updated the docstrings and added the test for unrecognized gates. I also added a test_diagonal_gates_commute_before_measurement case just to double-check that the commutation logic holds up when multiple diagonal gates are stacked. Let me know if that looks good." |
Description
Implemented the
drop_diagonal_before_measurementtransformer .This transformer identifies diagonal gates (Z, S, T, CZ, etc.) that are immediately followed by measurements. Since diagonal gates commute with the computational basis measurement, they can be removed without affecting the outcome probabilities.
Implementation Details:
eject_zfirst to push Z gates as far right as possible (handling the Z-CZ commutation case described in the issue).CZ(q0, q1)followed byMeasure(q0)is NOT removed (to preserveq1's phase).CZ(q0, q1)followed byMeasure(q0), Measure(q1)IS removed.Testing:
Added
diagonal_optimization_test.pycovering:Fixes #4935