-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Decompose controlled 1x1 unitary gates generically, not just GlobalPhaseGate #7283
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
Changes from 1 commit
93986f9
bf8cff7
77188f5
a55ebe8
3be4287
2a48fc6
bbb073a
41e1031
fd11a20
8aaba7d
1fa7e1f
8b9f2eb
2815738
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -177,18 +177,21 @@ def _decompose_with_context_( | |
protocols.unitary(self.sub_gate), control_qubits, qubits[-1] | ||
) | ||
return invert_ops + decomposed_ops + invert_ops | ||
if isinstance(self.sub_gate, gp.GlobalPhaseGate): | ||
# A controlled global phase is a diagonal gate, where each active control value index | ||
# is set equal to the phase angle. | ||
# Handle global phase gates by checking if the unitary is a 1x1 matrix with a global phase | ||
unitary = protocols.unitary(self.sub_gate, default=None) | ||
if ( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I was thinking this branch could be merged with the above branch. The conditions |
||
unitary is not None | ||
and unitary.shape == (1, 1) | ||
and np.isclose(np.abs(unitary[0, 0]), 1) | ||
): | ||
shape = self.control_qid_shape | ||
if protocols.is_parameterized(self.sub_gate) or set(shape) != {2}: | ||
# Could work in theory, but DiagonalGate decompose does not support them. | ||
return NotImplemented | ||
angle = np.angle(complex(self.sub_gate.coefficient)) | ||
angle = np.angle(unitary[0, 0]) | ||
rads = np.zeros(shape=shape) | ||
for hot in self.control_values.expand(): | ||
rads[hot] = angle | ||
return dg.DiagonalGate(diag_angles_radians=[*rads.flatten()]).on(*qubits) | ||
return dg.DiagonalGate(diag_angles_radians=[*rads.flatten()]).on(*qubits) | ||
if isinstance(self.sub_gate, common_gates.CZPowGate): | ||
z_sub_gate = common_gates.ZPowGate(exponent=self.sub_gate.exponent) | ||
num_controls = self.num_controls() + 1 | ||
|
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.
protocols.unitary
can be expensive, and here it's being called for every subgate. Better to rely onprotocols.has_unitary
andprotocols.num_qubits
and/orprotocols.qid_shape
in the conditions, and then only callprotocols.unitary
from inside the branch.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.
New PR should fix both this and the discussion above. I removed the extra unit test for now as I'm not sure if it is really necessary.