Skip to content

Change merge_single_qubit_moments_to_phxz to support global phase. #7405

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 2 commits into
base: main
Choose a base branch
from

Conversation

codrut3
Copy link
Contributor

@codrut3 codrut3 commented Jun 1, 2025

This addresses an issue I found while working on #7291

Currently merge_single_qubit_moments_to_phxz will not merge moments that have a global phase, meaning that moments that could theoretically be merged are not. I updated it so that global phase is also supported. I added two tests to show the issue.

Perhaps this situation is not common right now, but if #7383 is committed and the flag is used, it may become more common. @daxfohl

Note that I'm not merging the global phase operations in a single one, because I'm thinking some phases could be parametrized; should I attempt to do this?

Currently the method will not merge moments that have a global phase,
meaning that moments that could theoretically be merged are not.
I changed it so that global phase is also considered.
@codrut3 codrut3 requested review from vtomole and a team as code owners June 1, 2025 17:18
@codrut3 codrut3 requested a review from 95-martin-orion June 1, 2025 17:18
@github-actions github-actions bot added the size: S 10< lines changed <50 label Jun 1, 2025
Copy link

codecov bot commented Jun 1, 2025

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 98.68%. Comparing base (e27d883) to head (47a442f).
Report is 1 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #7405   +/-   ##
=======================================
  Coverage   98.68%   98.68%           
=======================================
  Files        1112     1112           
  Lines       97709    97754   +45     
=======================================
+ Hits        96427    96472   +45     
  Misses       1282     1282           

☔ 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.
@daxfohl
Copy link
Collaborator

daxfohl commented Jun 1, 2025

Note that I'm not merging the global phase operations in a single one, because I'm thinking some phases could be parametrized; should I attempt to do this?

In theory, yes, but as things currently are, probably not. It's fine to merge parameterized gates; a coefficient of e.g. a + b + 0.3 will still work fine in sweeps if values for a and b are provided. But the problem is that global phase isn't the only kind of zero-qubit gate. There's MatrixGate, DiagonalGate, various varadic-qubit-count gates like BooleanHamiltonian, Identity, PauliStringPhasor, etc. In theory they could all be converted to global phase by getting the 1x1 unitary, but parameterized gates generally return NotImplemented for the _unitary_ implementation. Plausibly there could be timing gates or pure classical logic gates or debug "gates" that don't even have unitaries. So, while ideally we could merge them, I don't think things are in a state currently where we could do so. Plausibly "have all zero-qubit gates 'decompose' to a global phase gate" could be a new feature request, which would make this more feasible.

Note that in #7383 the default behavior is unchanged; the phase shift doesn't get extracted during decomposition except when it's controlled, or if users explicitly set the phase extraction flag.

I'd say in this one, it maybe should have a flag to control this behavior as well? If users are explicitly setting the phase extraction flag in decomposition, then maybe they want to keep the phases in separate moments. Or if they have custom gates like pure classical logic or timing, they might not want those to collapse to a single moment by default. Hard to say for sure. Maybe get some feedback from @tanujkhattar who did the initial implementation?

@@ -118,7 +118,7 @@ def merge_single_qubit_moments_to_phxz(

def can_merge_moment(m: cirq.Moment):
return all(
protocols.num_qubits(op) == 1
(protocols.num_qubits(op) == 1 or protocols.num_qubits(op) == 0)
Copy link
Collaborator

Choose a reason for hiding this comment

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

<= 1?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

@codrut3
Copy link
Contributor Author

codrut3 commented Jun 2, 2025

I'd say in this one, it maybe should have a flag to control this behavior as well? If users are explicitly setting the phase extraction flag in decomposition, then maybe they want to keep the phases in separate moments. Or if they have custom gates like pure classical logic or timing, they might not want those to collapse to a single moment by default. Hard to say for sure. Maybe get some feedback from @tanujkhattar who did the initial implementation?

Thank you a lot for your reply @daxfohl ! Do you suggest that merging global phases should be behind a flag?

I think the benefit of this PR is that it allows merging more moments than before. merge_single_qubit_moments_to_phxz is called during conversion to a target gateset, so I believe this would improve some circuits. The only example I had came after extracting global phase in #7291, but it's possible there are circuits right now that would benefit from this PR.

@daxfohl
Copy link
Collaborator

daxfohl commented Jun 3, 2025

Do you suggest that merging global phases should be behind a flag?

No, I wouldn't worry about merging the global phases. That could be a subsequent change or even a separate transformer. What I means is that I think the functionality that's already in this PR should maybe require a parameter to enable it. I'm not terribly worried about it causing problems with global phase ops getting moved around, or that the extra efficiency allowing more ops to be placed in a moment would cause problems. Those aspects should be fine. I'm more concerned that things like classical logic gates, timing gates, or other random zero-qubit non-global-phase "utility" gates would also be affected, possibly in a breaking way.

That concern comes with a caveat though: IDK whether google's internal repos define or use such types of zero-qubit utility gates (I can't think of any such gates in cirq proper, but I know qiskit and q# both have things like this). If not, then probably this feature can go as-is. But if so, then the effect of this change needs to be considered for such gates.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
size: S 10< lines changed <50
2 participants