Skip to content

feat: added tomography result class - #863

Merged
jasonhan3 merged 9 commits into
mainfrom
jasonh/add-tomographyresult
Sep 28, 2026
Merged

jasonhan3 merged 9 commits into
mainfrom
jasonh/add-tomographyresult

Conversation

@jasonhan3

@jasonhan3 jasonhan3 commented Sep 17, 2026 •

Copy link
Copy Markdown
Contributor
  • Added a class for getting Tomography from shot counts.

Wanted to create a PR to start the discussion of adding a TomographyResult class, in order to reconstruct a quantum state from basis measurements

I think it's related to this issue: #529

@github-actions

github-actions Bot commented Sep 17, 2026 •

Copy link
Copy Markdown
Contributor

☂️ Code Coverage

current status: ✅

Overall Coverage

Statements Covered Coverage Threshold Status
13583 12177 90% 0% 🟢

New Files

File Coverage Status
src/bloqade/analysis/tomography/_init_.py 100% 🟢
src/bloqade/analysis/tomography/tomography.py 96% 🟢
TOTAL 98% 🟢

Modified Files

No covered modified files...

updated for commit: 78ac017 by action🐍

@codecov

codecov Bot commented Sep 17, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 96.55172% with 2 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/bloqade/analysis/tomography/tomography.py 96.49% 2 Missing ⚠️

📢 Thoughts on this report? Let us know!

@david-pl david-pl 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.

There's a tricky issue with normalization, and the frozen dataclass feels off.


import numpy as np

BASES = ("X", "Y", "Z")

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.

You convert this to a set a few times and all other usage, as far as I can tell, would also work if you just made this a set.

BASES = ("X", "Y", "Z")


def _density_matrix_from_bloch(bloch: Mapping[str, float]) -> np.ndarray:

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.

Hm, this is tricky: mixed states are not normalized, but if you leave things unnormalized then you can get a bloch vector with norm > 1 leading to invalid density matrices:

import numpy as np
from bloqade.analysis.tomography import TomographyResult
shots = {basis: np.array([0]) for basis in ("X", "Y", "Z")}
result = TomographyResult(shots)
print(np.linalg.eigvalsh(result.density_matrix))  # negative eigenvalue is not valid

A solution to fix the above would be to normalize if norm > 1, but that doesn't guarantee that the norm of a Bloch vector for a mixed state is too large so long as it's < 1.

@jasonhan3 jasonhan3 Sep 21, 2026 •

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.

I see, yeah this is tricky. I was looking into other quantum computing libraries, and a common pattern is to have some kind of "fitter" that finds the most likely physically valid density matrix given the measurement outcomes (examples: Forest-Benchmarking, Qiskit). We could do something similar, and have a DensityMatrix object instead? And add methods for computing fidelity to other states to that class (such as def fidelity_bloch(target_bloch: np.ndarray)).

To implement this DensityMatrix object, we could probably reuse the existing QuantumState class (

class QuantumState(NamedTuple):
), as it seems to serve a similar purpose (to represent density matrices).

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.

This sounds like a good idea. I'd be happy to refactor the QuantumState class, but it might lead to breaking changes, which I'm not sure we'll want. Also, I'm not sure how much work this will be.

An alternative would be to document the behavior here saying that things aren't normalized for now and then leave the rest for a follow-up ticket. I'll leave that up to you.

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.

I think we can keep the TomographyResult class as is and define the "fitter" methods on the class as alternative constructors. And regarding interoperability with the QuantumState class, in a future PR we can inherit from it (won't do so now as a lot of the methods in the QuantumState class are not implemented)

return overlap + 2.0 * math.sqrt(max(det_product, 0.0))


@dataclass(frozen=True, init=False)

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.

Having a frozen dataclass with a mutable field (you can mutate the density matrix, and you set it in the __init__) and a custom __init__ is odd, I think. I'd suggest to at least remove the frozen=True. Might also make sense to make the __init__ a __post_init__. Or, maybe even don't make it a dataclass at all if you need the __init__?

@jasonhan3 jasonhan3 added the backport v0.15 backport PRs to release-0-15 label Sep 22, 2026
@jasonhan3
jasonhan3 merged commit aecd13f into main Sep 28, 2026
12 checks passed
@jasonhan3
jasonhan3 deleted the jasonh/add-tomographyresult branch September 28, 2026 13:50
@github-actions

Copy link
Copy Markdown
Contributor

Backport results for aecd13f

Succeeded:

jasonhan3 pushed a commit that referenced this pull request Sep 28, 2026
Automated backport of PR #863 (aecd13f)
to `release-0-15`.

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backport v0.15 backport PRs to release-0-15

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants