Skip to content

Add native Clifford map compilation pass #476

Merged
matulni merged 19 commits into
TeamGraphix:masterfrom
matulni:clifford-extraction-clean
Apr 30, 2026
Merged

Add native Clifford map compilation pass #476
matulni merged 19 commits into
TeamGraphix:masterfrom
matulni:clifford-extraction-clean

Conversation

@matulni
Copy link
Copy Markdown
Contributor

@matulni matulni commented Apr 2, 2026

This PR adds a new compilation pass to natively synthesise (unitary) Clifford maps. It subsumes the stim compilation pass recently introduced in graphix-stim-compiler so that it is possible to do the Pattern -> Circuit conversion without external dependencies:

from graphix.transpiler import Circuit

qc = Circuit(2)
qc.cnot(1, 0)
qc.rz(0, 0.2)
qc.h(0)
print(qc)  # Circuit(width=2, instr=[CNOT(0, 1), RZ(0, pi/5), H(0)])

pattern = qc.transpile().pattern
qc_extracted = pattern.extract_opengraph().extract_circuit()
print(qc_extracted)  # Circuit(width=2, instr=[H(1), H(0), CNOT(1, 0), H(1), H(0), H(0), RX(0, pi/5)])

s_ref = qc.simulate_statevector().statevec
s_extracted = qc_extracted.simulate_statevector().statevec
assert s_ref.isclose(s_extracted)

Summary of changes

  • Introduced new methods: OpenGraph.extract_circuit, CliffordMap.to_tableau and new function graphix.circ_ext.compilation.cm_berg_pass.

Further, some improvements in the existing circuit extraction API are made:

  • Added new field dim to PauliString to represent the dimension of the Hilbert space.
  • Define PauliString on qubit indices and remove all remap methods.
  • Represent x_map and z_map attributes of CliffordMap as sequences of PauliString instead of mappings.

Discussion

This PR implements a custom adaptation of van den Berg's sweeping algorithm introduced in Ref. [1]. We note that in this paper their objective is to sample random Clifford operators, so here have to be a bit more careful to obtain the correct Clifford operator. Namely, we have to:

  • compute the adjoint of the compiled Clifford,
  • properly account for the sign phases
  • perform column operation on the full tableau instead of two-rows subtableaus.

The last point is crucial since the (naive) implementation in this PR may increase the reported $O(n^2)$ complexity. I list below some open questions beyond the scope of this PR:

  • What is the complexity scaling of this implementation and how does it compare to Stim's version ? (This should be easy to do, since the stim pass in graphix-stim-compiler allows to make sensible comparisons between both methods without much glue code).

  • Do we find an $O(n^2)$ complexity (which to my knowledge is the best-known bound)? If not, it may be worth exploring the algorithms in Ref. [2].

  • Explore Ref. [3] to synthesise Clifford isometries (corresponding to open graphs with larger number of outputs than inputs). This is particularly interesting since stim does not support these objects but it requires some prior work to represent circuit with ancillas in Graphix.

  • Explore Ref. [4] to synthesise Clifford unitaries on a given qubit topology. This should not be too complicated, since their algorithm is based on van den Berg's algorithm implemented here.

  • Finally, a vague idea: one of the virtues of the Pauli exponential DAG + Clifford map form in Simmon's paper is that it splits the Clifford and the non-Clifford part. Now, our compilation passes stitch both parts together in a single circuit. It would be more interesting to engineer an interface with stim (or some custom simulator), so that we can classically simulate the Clifford part, and somehow represent the output state as a stabilizer state that we pass to the PdDAG part.

References

[1] Van Den Berg, 2021. A simple method for sampling random Clifford operators (arXiv:2008.06011)
[2] Bravyi and Maslov, 2020, Hadamard-free circuits expose the structure of the Clifford group. (arXiv:2003.09412)
[3] Brugière et al., 2025, A graph-state based synthesis framework for Clifford isometries (arXiv:2212.06928)
[4] Winderl et al., 2024, Architecture-Aware Synthesis of Stabilizer Circuits from Clifford Tableaus (arXiv:2309.08972)

@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 2, 2026

Codecov Report

❌ Patch coverage is 97.29730% with 3 lines in your changes missing coverage. Please review.
✅ Project coverage is 89.94%. Comparing base (0dbdf66) to head (df2aced).
⚠️ Report is 1 commits behind head on master.

Files with missing lines Patch % Lines
graphix/circ_ext/compilation.py 97.10% 2 Missing ⚠️
graphix/circ_ext/extraction.py 97.43% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master     #476      +/-   ##
==========================================
+ Coverage   89.34%   89.94%   +0.60%     
==========================================
  Files          47       47              
  Lines        6891     6965      +74     
==========================================
+ Hits         6157     6265     +108     
+ Misses        734      700      -34     

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

@matulni matulni requested review from emlynsg and pranav97nair April 13, 2026 15:33
@emlynsg emlynsg linked an issue Apr 14, 2026 that may be closed by this pull request
Comment thread graphix/circ_ext/compilation.py
Comment thread graphix/circ_ext/compilation.py Outdated
Comment thread graphix/circ_ext/compilation.py Outdated
Comment thread graphix/circ_ext/compilation.py Outdated
Comment thread graphix/circ_ext/compilation.py Outdated
Comment thread graphix/circ_ext/compilation.py Outdated
Comment thread graphix/circ_ext/compilation.py Outdated
Comment thread graphix/circ_ext/compilation.py Outdated
Comment thread graphix/circ_ext/extraction.py Outdated
Comment thread graphix/circ_ext/extraction.py Outdated
Comment thread graphix/circ_ext/compilation.py Outdated
matulni and others added 2 commits April 16, 2026 10:01
@matulni
Copy link
Copy Markdown
Contributor Author

matulni commented Apr 21, 2026

Hi @thierry-martinez and @emlynsg.

I concluded that it's not a good idea to remove the input_nodes and output_nodes fields from CliffordMap. These attributes specify the embedding of the Clifford map in a Hilbert space (in the same way as in open graphs or patterns). If we remove them, we could still recover the nodes from x_map and z_map, but we lose the ordering between nodes, so the Clifford map is ill defined. The same logic applies to PauliExponentialDAG.

However, I took from the discussion that it's weird that .remap methods don't act on the input node list and output node list. There's indeed no need to keep this trace of the past, and CliffordMap.remap should return a fully valid CliffordMap. In commit b3ac6be I modify remap to act on all attributes. I added tests to show that CliffordMap.remap().remap() is equivalent to CliffordMap.remap() if we use the same mapping, and that we have recover the original object if we use the inverse mapping. Now, .to_tableau checks that the Clifford map has been remapped by comparing the list element and not just their lengths as suggested by Emlyn's comment. To simplify the use of to_tableau, I added a default value to .remap so that nodes are mapped to qubit indices automatically (another advantage of having input_nodes and output_nodes as attributes of CliffordMap).

Finally, in commit 5ef2fb2 I added a new field dim to PauliString so that these objects are fully determined on their own.

Ready for another round of review!

Edit: This PR updates the stim compiler plugin to comply with the new field in PauliString

Comment thread graphix/circ_ext/extraction.py
@matulni
Copy link
Copy Markdown
Contributor Author

matulni commented Apr 28, 2026

Commit 57790dc updates the API to incorporate the changes discussed this morning: namely PauliString is defined as a mapping from qubit indices to Axes so that it's unambiguously determined, and mappings in CliffordMap are defined over qubit indices as well. The now unnecessary remap functions are removed.

Copy link
Copy Markdown
Contributor

@emlynsg emlynsg left a comment

Choose a reason for hiding this comment

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

All makes sense to me!

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 am still wondering if the type alias Qubit is needed (cf. my comment in compilation.py) but this looks very good overall.

@matulni
Copy link
Copy Markdown
Contributor Author

matulni commented Apr 30, 2026

LGTM! I am still wondering if the type alias Qubit is needed (cf. my comment in compilation.py) but this looks very good overall.

You are right, I had forgotten about that. I removed the unnecessary type alias in 1b048f5

In df2aced, I renamed the class property PauliFlow.pauli_strings as PauliFlow.extraction_pauli_strings because I think it's more clear.

I'll merge if CI passes!

@matulni matulni merged commit be1f9d2 into TeamGraphix:master Apr 30, 2026
24 checks passed
@matulni matulni mentioned this pull request Apr 30, 2026
matulni added a commit to qat-inria/graphix-stim-compiler that referenced this pull request May 12, 2026
This commit updates the repository to make it compatible with the new `dim` field in `PauliString`. See TeamGraphix/graphix#476

---------

Co-authored-by: thierry-martinez <thierry.martinez@inria.fr>
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.

Unitary from pattern

3 participants