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

Implement LinearOperator protocol for SparsePauliOp #13490

Open
kevinsung opened this issue Nov 25, 2024 · 4 comments
Open

Implement LinearOperator protocol for SparsePauliOp #13490

kevinsung opened this issue Nov 25, 2024 · 4 comments
Labels
mod: quantum info Related to the Quantum Info module (States & Operators) type: feature request New feature or request
Milestone

Comments

@kevinsung
Copy link
Contributor

kevinsung commented Nov 25, 2024

What should we add?

Doing linear algebra with a SparsePauliOp typically involves converting it to a sparse matrix, which takes a very long time. However, many linear algebra tasks don't require explicit storage of all of the matrix elements, but merely require knowledge of how the operator transforms a vector. SciPy has a protocol to capture this concept called LinearOperator, which is a level of abstraction above sparse matrix. We should implement this for SparsePauliOp. There are at least two possible ways to do this:

  1. Have SparsePauliOp subclass LinearOperator, which would involve implementing at least the method _matvec that defines how the operator acts on a vector.
  2. Make a separate function that converts a SparsePauliOp to a LinearOperator.
@kevinsung kevinsung added the type: feature request New feature or request label Nov 25, 2024
@jakelishman jakelishman added this to the 2.0.0 milestone Nov 25, 2024
@jakelishman
Copy link
Member

Copied from my Slack messages, for further context:

LinearOperator is applied to dense vectors (as Numpy arrays), so it’s going to have the same 2^n complexity implication (for storage of the statevector) as the CSR form of to_matrix. If that’s still useful, we can look into it.

I think we might not be able to have SparsePauliOp directly subclass LinearOperator because of incompatible subclass typing in the methods (though I could be wrong - I haven’t looked in detail, but SparsePauliOp definitely already provides some methods of those names, and the behaviours might not be compatible). If it’s not possible to do directly, then one thing we could do would be to add a to_linear_operator method to SparsePauliOp that returns an opaque LinearOperator that fulfils the interface.

That said, it’s still not going to let SparsePauliOp (or SparseObservable) scale to 30q for such linear algebra operations, because the statevector representation will still be bounded.

[T]he matrix/vector product will take a similar amount of time as the conversion to CSR, because it scales the same way.

Actually, tbf, there’s better ways of writing that algorithm so it doesn’t scale as poorly, especially if all the contained Paulis are low weight,
though that relies on the matvec method allowing you to mutate the vector in place, rather than returning a new one. If we have to return a new one, there’s no way to escape the 2^n scaling of the method.

@jakelishman jakelishman added the mod: quantum info Related to the Quantum Info module (States & Operators) label Nov 25, 2024
@willkirby1
Copy link

FWIW I have an existing workaround for this (private repo) that does not use LinearOperators but just directly does matrix-free multiplication of SparsePauliOps on Scipy dok_arrays. I don't know if that is the optimal sparse vector format for performance, but what I have is scalable. In terms of practicality, it does allow multiplying e.g. a linear combination of 100000 computational basis vectors by a 40ish qubit SparsePauliOp. I haven't carefully checked how far it can be pushed. LMK if this is of interest, or if we are really wedded to using LinearOperators.

@jakelishman
Copy link
Member

jakelishman commented Nov 25, 2024

This is one more reason to use a to_linear_operator approach, so we don't cloud the main class with less efficient methods - dense arrays of course don't scale, even if the operator is matrix free.

Fwiw, dok_array will be totally fine if for computational basis vectors if you're manipulating them from Python and they stay very sparse. It's not so good for linear-algebra manipulation from Rust, though, because it stores all its data in Python formats, which makes it very slow for us to access. DOK is the cleanest for scalar indexing operations, since all of those are single hash lookups. For iterative update access (like matvec), the most efficient will be something that stores the indices in one array and the corresponding coefficients in another - a slight generalisation of the compressed-sparse formats, though iirc, scipy's implementation of those is limited to 2D. A csc format statevector with explicit shape (1, 2**n) is the closest to the ideal format, most likely (I didn't put a huge amount of thought into it), but indexing operations on that go as $\mathcal O\bigl(\lg(\text{nnz})\bigr)$ rather than constant-time (assuming the statevector is in canonical order - if it's unsorted, it's $\mathcal O\bigl(\text{nnz}\bigr)$, short of using Grover's lol).

@jakelishman
Copy link
Member

jakelishman commented Nov 25, 2024

When I say "very slow", I mean relative to what we should be able to achieve in Rust. Writing the same thing from Rust would still be approximately as fast as a pure Python-space implementation, maybe even a hair faster because of reduced loop overhead, but we'd still be bottlenecked on accesses to Python objects.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
mod: quantum info Related to the Quantum Info module (States & Operators) type: feature request New feature or request
Projects
None yet
Development

No branches or pull requests

3 participants