Skip to content

Fall back to unitary protocol in cirq.mixture for decomposable unitaries - #8406

Open
himmat05 wants to merge 5 commits into
quantumlib:mainfrom
himmat05:fix/mixture-decomposable-unitary-8402
Open

himmat05 wants to merge 5 commits into
quantumlib:mainfrom
himmat05:fix/mixture-decomposable-unitary-8402

Conversation

@himmat05

@himmat05 himmat05 commented Oct 4, 2026

Copy link
Copy Markdown

Fixes #8402

Description

cirq.has_mixture(val) returns True for decomposable unitary objects (such as Moment and CircuitOperation), but cirq.mixture(val) was raising TypeError because it only inspected val._unitary_ and never fell back to cirq.has_unitary(val) / cirq.unitary(val).

This PR aligns cirq.mixture with cirq.kraus by falling back to cirq.unitary(val) whenever cirq.has_unitary(val) is True.

Testing

  • Added test_mixture_decomposable_unitary testing cirq.Moment and cirq.CircuitOperation.
  • Ran all protocol tests in cirq-core/cirq/protocols/ (1228 passed).

Resolves quantumlib#8402 by falling back to cirq.has_unitary(val) and cirq.unitary(val) when an object lacks a direct _mixture_ or _unitary_ method. This matches the behavior of cirq.has_mixture and cirq.kraus for decomposable unitary objects such as Moment and CircuitOperation.

Signed-off-by: Himmat Sirwee <himmatsirwee05@gmail.com>
@himmat05
himmat05 requested a review from a team as a code owner October 4, 2026 16:16
@himmat05
himmat05 requested review from arettig and dabacon October 4, 2026 16:16
@google-cla

google-cla Bot commented Oct 4, 2026

Copy link
Copy Markdown

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

@github-actions github-actions Bot added the size: S 10< lines changed <50 label Oct 4, 2026
@codecov

codecov Bot commented Oct 6, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 99.59%. Comparing base (1403830) to head (056ae11).

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #8406   +/-   ##
=======================================
  Coverage   99.59%   99.59%           
=======================================
  Files        1133     1133           
  Lines      103919   103934   +15     
=======================================
+ Hits       103498   103513   +15     
  Misses        421      421           

☔ View full report in Codecov by Harness.
📢 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.

@arettig arettig self-assigned this Oct 6, 2026

@arettig arettig left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Hello, thanks for looking into this. I have a couple minor comments below. The main thing is that now that mixture can build the unitary from the decomposition, we should not call that potentially slow function from has_mixture.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

has_mixture should also be changed. Here, mixture will now form the full unitary via decomposition if possible, which can be very large/slow and disregards the allow_decompose parameter. Since the decomposition is checked above, this should change to just call _mixture_ here if it exists.


def test_mixture_decomposable_unitary() -> None:
q0, q1 = cirq.LineQubit.range(2)
for val in [

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Please use pytest.mark.parameterize rather than a loop here.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Please update this docstring as well.

- In has_mixture: check _mixture_ directly on fallback instead of calling
  mixture(val), avoiding expensive unitary construction through decomposition
  and respecting allow_decompose.
- Update mixture docstring to describe unitary fallback behavior.
- Use pytest.mark.parametrize in test_mixture_decomposable_unitary instead of a loop
  and add test verifying allow_decompose=False.

Signed-off-by: Himmat Sirwee <himmatsirwee05@gmail.com>
@himmat05
himmat05 force-pushed the fix/mixture-decomposable-unitary-8402 branch from 072c785 to b440201 Compare October 10, 2026 18:44
@himmat05

Copy link
Copy Markdown
Author

Hi @arettig , thanks for the review!

I've addressed all the requested changes in the latest commit:

has_mixture: Replaced the fallback call to mixture(val, None) with directly checking mixture. This prevents constructing full unitaries via decomposition and properly honors the allow_decompose parameter. Added test_has_mixture_allow_decompose_false to verify this behavior.
mixture docstring: Updated the Returns: and Raises: sections to document the unitary fallback behavior, default value handling, and accurate TypeError conditions.
Test refactor: Parametrized test_mixture_decomposable_unitary using @pytest.mark.parametrize instead of a for loop.
All protocol tests and lint checks are passing.

Signed-off-by: Himmat Sirwee <himmatsirwee05@gmail.com>
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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

cirq.has_mixture returns True but cirq.mixture raises TypeError for decomposable unitary objects

2 participants