Skip to content

Improve controlled gate decomposition logic and add targeted unit tests #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

Open
wants to merge 7 commits into
base: main
Choose a base branch
from

Conversation

RevanthGundala
Copy link
Contributor

@RevanthGundala RevanthGundala commented Apr 17, 2025

Summary

Fixes #7248

This PR improves the decomposition logic for controlled gates in Cirq, ensuring that controlled 1x1 MatrixGate and GlobalPhaseGate instances decompose correctly. It also adds a targeted unit tests to verify this behavior.

Details

  • Updated the decompose_with_context method in cirq-core/cirq/ops/controlled_gate.py to:
    • Correctly handle controlled gates with 1x1 unitary (global phase) by decomposing them into a DiagonalGate with the correct phase.
  • Added a parameterized test and additional explicit unit tests in cirq-core/cirq/ops/controlled_gate_test.py to:
    • Check that controlled global phase gates decompose to the correct diagonal structure for various phases and control configurations.

Supersedes #7282

@RevanthGundala RevanthGundala requested review from vtomole and a team as code owners April 17, 2025 23:21
# 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 (
Copy link
Collaborator

Choose a reason for hiding this comment

The 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 protocols.has_unitary(self.sub_gate) and self._qid_shape_() == (2,) * len(self._qid_shape_()) apply to both. The global phase inner branch would then just need an extra check for protocols.num_qubits(self.sub_gate) == 0. The if protocols.is_parameterized(self.sub_gate) or set(shape) != {2}: check can be removed, because parameterized gates fail has_unitary, and set(shape) == {2} is equivalent to the self_qid_shape_() condition. There's also no need for the three conditions you added, since zero qubits implies a 1x1 unitary, and the abs of a unitary must square-sum to 1 by definition.

# 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)
Copy link
Collaborator

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 on protocols.has_unitary and protocols.num_qubits and/or protocols.qid_shape in the conditions, and then only call protocols.unitary from inside the branch.

Copy link
Contributor Author

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.

Copy link

codecov bot commented Apr 18, 2025

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 98.66%. Comparing base (5112418) to head (bbb073a).
Report is 10 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #7283      +/-   ##
==========================================
- Coverage   98.66%   98.66%   -0.01%     
==========================================
  Files        1106     1106              
  Lines       96086    96098      +12     
==========================================
+ Hits        94808    94819      +11     
- Misses       1278     1279       +1     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link
Collaborator

@daxfohl daxfohl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it still needs a unit test. Unlike the one you deleted, the unit test should directly check the new decomposition functionality. Previously, controlled GlobalPhaseGates would decompose but equivalent controlled MatrixGates wouldn't. So a unit test could check that controlled MatrixGate now decomposes to the same thing that an equivalent controlled GlobalPhaseGate does.

and protocols.num_qubits(self.sub_gate) == 1
and self._qid_shape_() == (2,) * len(self._qid_shape_())
and isinstance(self.control_values, cv.ProductOfSums)
if protocols.has_unitary(self.sub_gate) and self._qid_shape_() == (2,) * len(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While you're here, can you change the second condition to all(q.dimension == 2 for q in qubits) since it's equivalent and more readable?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added the unit test + swapped order of branches since the matrix gate seems like more of an edge case. Doesn't change logic though.

Copy link
Collaborator

@daxfohl daxfohl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm cc @pavoljuhas

@github-actions github-actions bot added the size: M 50< lines changed <250 label Apr 30, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
size: M 50< lines changed <250
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Allow decomposition of controlled 1x1 MatrixGate
2 participants