Skip to content

[open-systems] Superoperator tensor contraction #1596

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

Merged
merged 77 commits into from
Jul 14, 2025

Conversation

mpharrigan
Copy link
Collaborator

@mpharrigan mpharrigan commented Mar 14, 2025

This pull request is the third in a series for supporting open system (classical data & measurement), roadmap item #445.

This branch is based on #1590 (for my convenience; it doesn't use any of that functionality)

Bloq.tensor_contract(superoperator=True)

This is the new interface. It will return a 0-, 2-, or 4-dimensional tensor for constants, density matrices, and superoperators (resp) to support simulating programs with measurements and non-unitary maps. Read the docs for the indexing convention for the superoperator; but if you're really doing something with the superoperators you may want to operate on the quimb tensor network with friendly indices itself.

cbloq_to_superquimb

The workhorse of the new functionality is this function that converts a composite bloq to a tensor network that represents the density matrix and/or superoperator of the program. Some operations like measurement or discarding qubits cannot be represented in a pure-state statevector / unitary picture.

cbloq_to_superquimb still uses Bloq.my_tensors to construct the network. It adds each tensor twice: once in the "forward" direction and again in the "backward" (adjoint) direction.

DiscardInd

The Bloq.my_tensors method can now return a DiscardInd object, which signifies that that tensor index should be discarded by tracing it out.

It turns out that this simple extension lets you represent any CPTP map using the "system+environment" modeling approach.

MeasZ, Discard

This PR includes two non-unitary maps: measuring in the Z basis and discarding a qubit or classical bit.

Manipulating quimb tensor networks

This PR makes some changes to the way we handle outer indices in the quimb tensor network. This should only be of interest to folks who use the "hands on" approach of directly manipulating the tensor networks. The changes make sense and clean up some of the docs.

The outer indices are now re-mapped to tuples of qualtran objects that actually make sense rather than keeping them as Connections to DanglingT objects. There is a new flag friendly_indices=True which will make the outer indices friendly strings.

breaking change I renamed and made-private the get_left_and_right_inds function. The original idea was to use this as a public way of getting a handle on the outer indices, but it was always tricky to use; and needed to be changed to support the new variety of outer indices present in the superoperator networks. No one should need a replacement for this function since the qtn.TensorNetwork object outer indices now just intrinsically make sense.

Non-changes

This includes the minimal set of non-unitary CPTP bloqs to support the docs notebooks.

@mpharrigan mpharrigan requested a review from tanujkhattar May 13, 2025 23:24
@mpharrigan mpharrigan marked this pull request as ready for review May 13, 2025 23:24
Copy link
Collaborator

@tanujkhattar tanujkhattar left a comment

Choose a reason for hiding this comment

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

@mpharrigan Is this blocked on something?

@NoureldinYosri Can you please take a look?

I'll be happy to LGTM and merge it since I want to use the functionality in this PR.

Copy link
Contributor

@NoureldinYosri NoureldinYosri left a comment

Choose a reason for hiding this comment

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

LGTM%nits

@@ -0,0 +1,68 @@
# Copyright 2024 Google LLC
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
# Copyright 2024 Google LLC
# Copyright 2025 Google LLC

@@ -0,0 +1,82 @@
# Copyright 2024 Google LLC
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
# Copyright 2024 Google LLC
# Copyright 2025 Google LLC

@cached_property
def signature(self) -> 'Signature':
return Signature(
[Register('q', QBit(), side=Side.LEFT), Register('c', CBit(), side=Side.RIGHT)]
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: if the measurement is nondemolition measurement then the qubit can be reused. which would be simpler than allocating a new qubit in the state indicated by the classical bit.

perhabs a boolean that controls whether the qubit is LEFT or TRHOUGH can be used here?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

That is certainly a valid operation, although I'd advocate for that being its own bloq.

The current construct is simpler if you're measuring a qubit to get its bit value

Copy link

Check out this pull request on  ReviewNB

See visual diffs & provide feedback on Jupyter Notebooks.


Powered by ReviewNB

@mpharrigan mpharrigan enabled auto-merge (squash) July 14, 2025 23:21
@mpharrigan mpharrigan merged commit 576835d into quantumlib:main Jul 14, 2025
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants