Skip to content

Add sparse_matrix() to PauliString and PauliSum#8127

Open
ToastCheng wants to merge 3 commits into
quantumlib:mainfrom
ToastCheng:i3057-sparse2
Open

Add sparse_matrix() to PauliString and PauliSum#8127
ToastCheng wants to merge 3 commits into
quantumlib:mainfrom
ToastCheng:i3057-sparse2

Conversation

@ToastCheng

@ToastCheng ToastCheng commented Jun 7, 2026

Copy link
Copy Markdown
Contributor

For each PauliString term, row/col indices and phases are computed directly via bitwise ops on basis states to avoid Kron product.

For PauliSum, uses COO triplet accumulation instead of repeated CSR addition to avoid merging multiple sparse matrices.

Fixes #3057

@ToastCheng ToastCheng requested a review from a team as a code owner June 7, 2026 06:53
@ToastCheng ToastCheng requested a review from tanujkhattar June 7, 2026 06:53
@github-actions github-actions Bot added the size: M 50< lines changed <250 label Jun 7, 2026
@codecov

codecov Bot commented Jun 7, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 99.60%. Comparing base (4738170) to head (a4faba8).
⚠️ Report is 17 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff            @@
##             main    #8127    +/-   ##
========================================
  Coverage   99.60%   99.60%            
========================================
  Files        1118     1118            
  Lines      100957   101112   +155     
========================================
+ Hits       100557   100712   +155     
  Misses        400      400            

☔ 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.

For each PauliString term, row/col indices and phases are computed
directly via bitwise ops on basis states to avoid Kron product.

For PauliSum, uses COO triplet accumulation instead of repeated CSR
addition to avoid merging multiple sparse matrices.
@mhucka

mhucka commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

@ToastCheng Thank you for this work!

@mhucka mhucka self-assigned this Jun 9, 2026

@mhucka mhucka 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.

Thank you for working on this!

I have some very small requests; otherwise, it looks good to me. I think @pavoljuhas had better review this too.

Comment thread cirq-core/cirq/ops/linear_combinations.py Outdated
Comment thread cirq-core/cirq/ops/pauli_string.py Outdated
Comment thread cirq-core/cirq/ops/pauli_string.py Outdated
Comment thread cirq-core/cirq/ops/pauli_string.py Outdated
Comment thread cirq-core/cirq/ops/linear_combinations.py Outdated
Comment thread cirq-core/cirq/ops/pauli_string.py Outdated
Comment thread cirq-core/cirq/ops/pauli_string.py Outdated
Comment thread cirq-core/cirq/ops/pauli_string.py Outdated
Comment thread cirq-core/cirq/ops/pauli_string_test.py Outdated
Comment thread cirq-core/cirq/ops/pauli_string_test.py Outdated
@mhucka mhucka requested a review from pavoljuhas June 10, 2026 04:43
In addition, update implementation details:
- use np.where parity check for phases
- iterate self.items() directly
@pavoljuhas pavoljuhas self-assigned this Jun 10, 2026
@pavoljuhas pavoljuhas added the priority/before-1.7 Finish before the Cirq 1.7 release label Jun 11, 2026
@pavoljuhas pavoljuhas requested a review from dstrain115 June 17, 2026 02:22
Comment thread cirq-core/cirq/ops/pauli_string.py
@mhucka

mhucka commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

@ToastCheng Thanks again for this contribution. Apart from agreeing with Pavol's point above, about adding an asserion, it's good to go from my perspective.

@pavoljuhas

Copy link
Copy Markdown
Collaborator

Thank you @mhucka. I asked @dstrain115 for a one quick look, so let's allow some time for that. Otherwise this looks good to me too.

@dstrain115 dstrain115 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Would recommend tightening up the test for pauli sum sparse matrix a bit, but otherwise I approve.

Comment thread cirq-core/cirq/ops/linear_combinations_test.py Outdated
assert np.allclose(H3, paulisum.matrix([q[1], q[2], q[0]]))


def test_pauli_sum_sparse_matrix() -> None:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I would recommend parameterizing this test case and passing in a variety of pauli sums.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Updated

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.

@dstrain115 when you get a chance, would you review & approve the PR if it's ready?

@pavoljuhas pavoljuhas left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I have a couple of minor suggestions, otherwise this looks great. Thank you @ToastCheng for contributing this!

(cirq.X(q0) * cirq.I(q1) + cirq.Z(q1), None),
),
)
def test_pauli_sum_sparse_matrix(paulisum, qubits) -> None:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Nit - let us annotate the argument types here:

def test_pauli_sum_sparse_matrix(paulisum: cirq.PauliSum, qubits: list[cirq.Qid] | None) -> None:

def test_pauli_sum_sparse_matrix(paulisum, qubits) -> None:
actual = paulisum.sparse_matrix(qubits).toarray()
expected = paulisum.matrix(qubits)
assert np.allclose(actual, expected)

@pavoljuhas pavoljuhas Jun 24, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Nit - we should use np.array_equal here to ensure the shapes of compared arrays are the same. (All tested coefficients have exact binary representation so there should be no problem with roundoffs)

def test_pauli_sum_sparse_matrix_empty() -> None:
q = cirq.LineQubit.range(2)
empty = cirq.PauliSum.from_pauli_strings([])
assert np.allclose(empty.sparse_matrix(q).toarray(), np.zeros((4, 4)))

@pavoljuhas pavoljuhas Jun 24, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

We should use array_equal as above and we should also check the default sparse_matrix:

    assert np.array_equal(empty.sparse_matrix().toarray(), np.zeros((1, 1)))
    assert np.array_equal(empty.sparse_matrix(q).toarray(), np.zeros((4, 4)))


Raises:
NotImplementedError: If this `PauliString` is parameterized.
AssertionError: If an unexpected Pauli gate instance is encountered.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Nit - perhaps we should leave AssertionError from the docstring. Assertions are supposed to be always true regardless of user input; they should only pop up if there is a breaking change in the code or some unexpected code pathway.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

priority/before-1.7 Finish before the Cirq 1.7 release size: M 50< lines changed <250

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add sparse_matrix method to PauliSum

4 participants