Skip to content
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

Add partial transpose function in quantum_info #9566

Merged
merged 31 commits into from
Apr 17, 2023

Conversation

PayalSolanki2906
Copy link
Contributor

Summary

The partial transpose of a density matrix is a mathematical operation that transforms the matrix by interchanging only certain indices of the matrix elements. This operation is significant in the study of quantum entanglement as it provides information about the entanglement structure of a quantum system, with positive partial transpose indicating separable states and negative partial transpose indicating entangled states.

Details and comments

I and @pranay1990 have contributed to this code. We have added a new function named partial_transpose in quantum_info (under utility functions).

@qiskit-bot qiskit-bot added the Community PR PRs from contributors that are not 'members' of the Qiskit repo label Feb 10, 2023
@qiskit-bot
Copy link
Collaborator

Thank you for opening a new pull request.

Before your PR can be merged it will first need to pass continuous integration tests and be reviewed. Sometimes the review process can be slow, so please be patient.

While you're waiting, please feel free to review other open PRs. While only a subset of people are authorized to approve pull requests for merging, everyone is encouraged to review open pull requests. Doing reviews helps reduce the burden on the core team and helps make the project's code better for everyone.

One or more of the the following people are requested to review this:

@CLAassistant
Copy link

CLAassistant commented Feb 10, 2023

CLA assistant check
All committers have signed the CLA.

@woodsp-ibm woodsp-ibm added Changelog: New Feature Include in the "Added" section of the changelog mod: quantum info Related to the Quantum Info module (States & Operators) labels Feb 10, 2023
@coveralls
Copy link

coveralls commented Feb 13, 2023

Pull Request Test Coverage Report for Build 4706198971

  • 10 of 10 (100.0%) changed or added relevant lines in 1 file are covered.
  • 29 unchanged lines in 3 files lost coverage.
  • Overall coverage increased (+0.009%) to 85.793%

Files with Coverage Reduction New Missed Lines %
crates/accelerate/src/sabre_swap/layer.rs 4 97.32%
crates/qasm2/src/lex.rs 7 90.13%
crates/qasm2/src/parse.rs 18 96.65%
Totals Coverage Status
Change from base Build 4704167625: 0.009%
Covered Lines: 70498
Relevant Lines: 82172

💛 - Coveralls

Copy link
Contributor

@Cryoris Cryoris left a comment

Choose a reason for hiding this comment

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

Thanks for your contribution! I left some general comments below 🙂

raise QiskitError("Indices of subsystems to be transposed are invalid")
ptden = np.empty((2**n, 2**n), complex)
ptden[:] = np.nan
if isinstance(state, Statevector):
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't quite understand what a partial transpose of a vector is, do you have a definition for this? 🙂 Maybe this operation should only be supported for actual DensityMatrix objects, as you also mentioned in the typehint?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hey @Cryoris, it seems what you're saying is true. We had considered allowing input as a Statevector and converting it to a pure state density matrix, similar to partial trace code. However, if you're suggesting that it's not necessary, we can remove that option. Please let us know.

Copy link
Contributor

Choose a reason for hiding this comment

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

If a user would like to do that they could always construct the DensityMatrix explicitly and then use your function:

dm = DensityMatrix(state)
partial_transpose(dm, ...)

so I think you don't have to cover this case here 🙂

Comment on lines 197 to 199
for i in range(2**n):
for j in range(2**n):
if math.isnan(ptden[i, j]):
Copy link
Contributor

Choose a reason for hiding this comment

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

Could this loop be made more efficient by only visiting entries that we know need to be populated, or maybe transposing sub-blocks of the matrix all at once? As it is now, this scales as 2 ^ (2n) which is going to be very expensive.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We will try to optimize it.

Copy link
Member

Choose a reason for hiding this comment

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

For most operators, I would imagine you can do this in vectorised Numpy by casting state.data (a Numpy array) to a multi-dimensional tensor (e.g. using np.reshape(state.data, state._op_shape.tensor_shape) or something like that), calling np.transpose as appropriate, then restoring it to be a 2D array. If that's correct, then that should be much faster than looping in Python space.

quantum_info.Operator also isn't guaranteed to be square. I don't think the partial trace is reasonably defined for tensor-product spaces where the number of input and output spaces are unequal, but it could in theory work for things like a mapping of a (2, 3) Hilbert space to a (1, 4) one. Probably best not to worry about that, though, and just error out if the dims_r of the OpShape aren't equal to the dims_l.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@jakelishman This helps. Thank you.

"""
state = _format_state(state, validate=False)
n = len(state.dims())
lst = np.zeros(2**n, int)
Copy link
Contributor

Choose a reason for hiding this comment

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

The DensityMatrix also allows qudit subsystems (see the dims argument 🙂), but in this implementation you assume qubits. We'd either have to add a check that the input density matrix is defined on qubits or generalize this code to work on arbitrary dimensions.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thank you for bringing this to our attention. We will take steps to rectify the issue.

@PayalSolanki2906 PayalSolanki2906 requested review from ikkoham and jakelishman and removed request for Cryoris, ikkoham and jakelishman February 20, 2023 12:20
@PayalSolanki2906
Copy link
Contributor Author

@ikkoham requested changes have been incorporated, and we kindly request your assistance for further process.

@pranay1990
Copy link
Contributor

@ikkoham, @Cryoris, and @jakelishman, could any one of you please tell us what is the progress regarding the pull request?

Copy link
Contributor

@ikkoham ikkoham left a comment

Choose a reason for hiding this comment

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

Thank you. Sorry for late. This direction looks good to me.
inplace option can be optional and feature request in the future.

I left some comments.

"""
from qiskit.quantum_info.states import utils

state = utils._format_state(self, validate=False)
Copy link
Contributor

Choose a reason for hiding this comment

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

Why do you need _format_state and reshape? self is DensityMatrix by definition.

rho1[4, 5] = 0.5
rho1[5, 4] = 0.5
rho1[5, 5] = 0.5
self.assertEqual(DensityMatrix.partial_transpose(rho, [0, 1]), DensityMatrix(rho1))
Copy link
Contributor

Choose a reason for hiding this comment

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

DensityMatrix.partial_transpose is not classmethod, so DensityMatrix(rho).partial_transpose([0, 1]) is correct.

@ikkoham ikkoham added this to the 0.24.0 milestone Mar 23, 2023
@ikkoham ikkoham self-assigned this Apr 12, 2023
@ikkoham
Copy link
Contributor

ikkoham commented Apr 12, 2023

@PayalSolanki2906 @pranay1990 Thank you for your great contributions. I would like to merge this PR for 0.24. Please check my PR to your repo. PayalSolanki2906#1

@pranay1990
Copy link
Contributor

Thank you for allowing us to make our first contribution. We sincerely appreciate the support and guidance provided during the process, which made it very smooth for us. We are eager to continue contributing in the future and look forward to working with you again.

@pranay1990
Copy link
Contributor

Hi @ikkoham, after this pull request is merged, we would be interested in contributing towards the implementation of logarithmic negativity as an entanglement measure. We would appreciate your input on whether this is a feasible addition and would be grateful for any guidance or feedback you may have. Thank you for your time and consideration.

Copy link
Contributor

@ikkoham ikkoham left a comment

Choose a reason for hiding this comment

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

Thank you! LGTM.

For the log negativity, I think a function would be nice (not method), but let's discuss. I would be glad if you could make an issue,

@ikkoham ikkoham added this pull request to the merge queue Apr 17, 2023
@github-merge-queue github-merge-queue bot removed this pull request from the merge queue due to failed status checks Apr 17, 2023
@mtreinish mtreinish added this pull request to the merge queue Apr 17, 2023
Merged via the queue into Qiskit:main with commit 580590f Apr 17, 2023
ikkoham added a commit to ikkoham/qiskit-terra that referenced this pull request Apr 19, 2023
* partial_transpose included

* included partial_transpose

* included partial_transpose

* included partial_transpose

* included partial_transpose

* included partial_transpose

* included partial_transpose

* included partial_transpose

* included partial_transpose

* included partial_transpose

* included partial_transpose

* included partial_transpose

* included test for partial transpose

* included test for partial transpose

* included test for partial transpose

* added docstring

* included DensityMatrix(rho1)

* changed rho1

* addition of release note

* fix

* fix

* fir partial_transpose

* Update utils.py

* refactor and add tests

---------

Co-authored-by: Ikko Hamamura <ikkoham@users.noreply.github.com>
king-p3nguin pushed a commit to king-p3nguin/qiskit-terra that referenced this pull request May 22, 2023
* partial_transpose included

* included partial_transpose

* included partial_transpose

* included partial_transpose

* included partial_transpose

* included partial_transpose

* included partial_transpose

* included partial_transpose

* included partial_transpose

* included partial_transpose

* included partial_transpose

* included partial_transpose

* included test for partial transpose

* included test for partial transpose

* included test for partial transpose

* added docstring

* included DensityMatrix(rho1)

* changed rho1

* addition of release note

* fix

* fix

* fir partial_transpose

* Update utils.py

* refactor and add tests

---------

Co-authored-by: Ikko Hamamura <ikkoham@users.noreply.github.com>
@diemilio
Copy link
Contributor

Hello @ikkoham, @PayalSolanki2906, @pranay1990. I just bump into this new partial_transpose feature while searching thru the qiskit repo because it shares some similarities with the PR I am working on. While looking at the code, I noticed a small issue. If the density matrix is not for a qubit system (i.e., the dimensions are not for 2-level systems), the output density matrix will have different dimensions wrt the input density matrix.

This can be easily fixed by just having the function return

return DensityMatrix(rho, dims=self.dims())

Not sure if a separate PR needs to be issued since this one has already been merged, but happy to help if needed.

@jakelishman
Copy link
Member

Diego: if there's a bug, we'll need a PR to fix it. Could you open an issue with an example showing the bug, then you (or us, if you don't have time) can make a PR fixing it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Changelog: New Feature Include in the "Added" section of the changelog Community PR PRs from contributors that are not 'members' of the Qiskit repo mod: quantum info Related to the Quantum Info module (States & Operators)
Projects
Status: Done
Development

Successfully merging this pull request may close these issues.