Skip to content

Conversion methods for PauliString#507

Open
matulni wants to merge 6 commits into
TeamGraphix:masterfrom
matulni:ps-tools
Open

Conversion methods for PauliString#507
matulni wants to merge 6 commits into
TeamGraphix:masterfrom
matulni:ps-tools

Conversation

@matulni
Copy link
Copy Markdown
Contributor

@matulni matulni commented May 13, 2026

This commit introduces new methods for the PauliString class:

  • __str__ and from_str provide an interface with strings to simplify debugging,
  • to_tableau and from_tableau provide an interface with the _linalg module to facilitate implementing algorithms based on the stabilizer formalism.

Additionally, the static method PauliString.from_measured_node is subsumed by the function extraction_ps_from_corrected_node. This follows from the observation that the returned Pauli string is truly specific to the circuit extraction algorithm, and it's not the canonical stabilizer given by a flow's correction function. The latter reads

$$ S_i = Z_i K_i = Z_i X_{g(i)\setminus \{i\}} Z_{\text{Odd}[g(i)]\setminus \{i\}},$$

whereas the extraction_ps_from_corrected_node returns a Pauli string acting on the output nodes only. Work on MBQC fidelity shows that PauliString objects are useful beyond the circuit extraction routine, so this refactor aims at giving the PauliString class more independence.

TODO

Up changelog

@codecov
Copy link
Copy Markdown

codecov Bot commented May 13, 2026

Codecov Report

❌ Patch coverage is 93.05556% with 5 lines in your changes missing coverage. Please review.
✅ Project coverage is 89.62%. Comparing base (222a292) to head (2107e51).

Files with missing lines Patch % Lines
graphix/circ_ext/extraction.py 92.85% 5 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master     #507      +/-   ##
==========================================
- Coverage   89.65%   89.62%   -0.03%     
==========================================
  Files          48       48              
  Lines        7015     7047      +32     
==========================================
+ Hits         6289     6316      +27     
- Misses        726      731       +5     

☔ View full report in Codecov by Sentry.
📢 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.

Copy link
Copy Markdown
Collaborator

@thierry-martinez thierry-martinez left a comment

Choose a reason for hiding this comment

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

LGTM! I've added a few comments, but they're mainly nit-picking.

Comment on lines +128 to +129
if len(ps) < 2:
raise ValueError("Input string must have at least 2 characters (a sign followed by operators).")
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.

Should we disallow empty Pauli strings?
Should the default sign be +?

For comparison:

>>> stim.PauliString("X")
stim.PauliString("+X")
>>> stim.PauliString("")
stim.PauliString("+")

In addition, PauliString.from_str(str(PauliString(0, {}))) now raises an exception. I'm not sure whether this behavior is intentional.

raise ValueError("Input string must have at least 2 characters (a sign followed by operators).")

References
sign_char, ops = ps[0], ps[1:] # Mypy disallows string unpacking
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.

In Python, string unpacking is just a particular case of iterable unpacking. For example,

sign_char, ops = ps[0], ps[1:]

uses slicing, so ops becomes a string. In contrast,

sign_char, *ops = ps

produces a list of characters for ops. For the rest of the code, the difference is irrelevant.

If you prefer the more declarative string-unpacking style, you can be explicit about using iterable unpacking; mypy accepts this:

Suggested change
sign_char, ops = ps[0], ps[1:] # Mypy disallows string unpacking
sign_char, *ops = iter(ps)

sign_char, ops = ps[0], ps[1:] # Mypy disallows string unpacking

_sign_map = {"+": Sign.PLUS, "-": Sign.MINUS}
_axis_map = {"X": Axis.X, "Y": Axis.Y, "Z": Axis.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.

The class Axis itself behaves much like a dictionary: Axis["X"] returns Axis.X. However, the expression "X" in Axis returns False. The proper mapping is Axis.__members__: "X" in Axis.__members__ returns True.

"""Return a string representation of the Pauli string."""
pauli_str = (
str(self.sign),
*(getattr(self.axes.get(node), "name", "I") for node in range(self.dim)),
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 prefer to avoid getattr because it isn't type-safe. Moreover, it's clearer to test explicitly whether an axis exists or not rather than relying on the fact that there is no field name in None.

Suggested change
*(getattr(self.axes.get(node), "name", "I") for node in range(self.dim)),
*(axis.name if (axis := self.axes.get(node)) else "I" for node in range(self.dim)),

)

tab = MatGF2(np.zeros((2 * n, 2 * n + 1)))
return MatGF2(np.vstack((*(ps.to_tableau() for ps in self.x_map), *(ps.to_tableau() for ps in self.z_map))))
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.

Suggested change
return MatGF2(np.vstack((*(ps.to_tableau() for ps in self.x_map), *(ps.to_tableau() for ps in self.z_map))))
return MatGF2(np.vstack([ps.to_tableau() for psmap in (self.x_map, self.z_map) for ps in psmap]))

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants