-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Simplify decomposition of controlled eigengates with global phase #7383
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?
Conversation
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## main #7383 +/- ##
=======================================
Coverage 98.68% 98.68%
=======================================
Files 1112 1112
Lines 97641 97707 +66
=======================================
+ Hits 96359 96426 +67
+ Misses 1282 1281 -1 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
@property | ||
def is_identity(self) -> bool: | ||
return ( | ||
not protocols.is_parameterized(self._coefficient) and abs(self._coefficient - 1.0) == 0 |
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 was moved from three_qubit_gates.py
line 120, but now that I look at it again, it seems equivalent to self.coefficient == 1
. Will try that and see if it works. If so, that's simple enough that the method probably doesn't even need to exist, and can just be inlined.
assert isinstance(gate0, cirq.EigenGate) | ||
assert gate0.global_shift == 0 | ||
assert gate0.exponent == exponent | ||
if exponent * 2 / 3 % 2 != 0: |
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.
Could be simplified to if exponent % 3:
@pytest.mark.parametrize('exponent', [0, 0.5, 2, 3, -0.5, -2, -3, sympy.Symbol('s')]) | ||
def test_decompose_with_extracted_phases(gate_type: type, exponent: cirq.TParamVal) -> None: | ||
context = cirq.DecompositionContext(cirq.SimpleQubitManager(), extract_global_phases=True) | ||
gate = gate_type(exponent=exponent, global_shift=2 / 3) |
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.
Make 2/3
a variable since it's used multiple times, and refer back to the docstring of _extract_phase
to explain why it's interesting.
control_qubits = list(qubits[: self.num_controls()]) | ||
controlled_sub_gate = self.sub_gate.controlled( | ||
self.num_controls(), self.control_values, self.control_qid_shape | ||
) | ||
# Prefer the subgate controlled version if available | ||
if self != controlled_sub_gate: | ||
return controlled_sub_gate.on(*qubits) | ||
|
||
# Try decomposing the subgate next. | ||
# Extract global phases from decomposition, as controlled phases decompose easily. |
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.
Move this comment five lines down.
@@ -802,3 +802,19 @@ def test_controlled_global_phase_matrix_gate_decomposes(num_controls, angle, con | |||
decomposed = cirq.decompose(cg_matrix(*all_qubits)) | |||
assert not any(isinstance(op.gate, cirq.MatrixGate) for op in decomposed) | |||
np.testing.assert_allclose(cirq.unitary(cirq.Circuit(decomposed)), cirq.unitary(cg_matrix)) | |||
|
|||
|
|||
def test_simplified_controlled_phased_eigengate_decomposition() -> None: |
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.
Add the other affected 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.
Actually it could be made more generic and parameterized: the decomposition should always be equal to the decomposition of the equivalent gate without global shift, plus a final Z gate.
Fixes #7238
DecomposeContext
to configure extraction of terminal gates' global phases into distinct GlobalPhaseGates.a. This flag defaults to False for backward compatibility.
a. Added some convenience methods in GlobalPhaseGate to help.
b. Updated some unrelated existing code to use these convenience methods for clarity.
ControlledGate.decompose
to attempt decompose the subgate before attempting the brute-force approach.a. This is what ultimately simplifies the decomposition result.
b. Step 2 also allowed removal of the entire CZPowGate instanceof block there, since it was about extracting global phase.