Skip to content

Add generate_clifford_t_pass_manager#15918

Open
alexanderivrii wants to merge 7 commits intoQiskit:mainfrom
alexanderivrii:generate-clifford-t-pass-manager
Open

Add generate_clifford_t_pass_manager#15918
alexanderivrii wants to merge 7 commits intoQiskit:mainfrom
alexanderivrii:generate-clifford-t-pass-manager

Conversation

@alexanderivrii
Copy link
Copy Markdown
Member

Summary

This PR introduces a function generate_clifford_t_pass_manager which is analogous to generate_preset_pass_manager but exposes arguments specifically tailored for Clifford+T compilation. In particular it does not have arguments such as init_stage or optimization_stage but has arguments rz_synthesis_error and rz_cache_error relevant to synthesizing RZ-gates to Clifford+T basis set.

The previously existing ways of instantiating a Clifford+T transpiler pipeline (via transpile or generate_preset_pass_manager with a Clifford+T basis set) are still supported, however using the new function is recommended.

Details and comments

I have defined the following classes:

  • PassManagerCliffordTConfig, which is analogous to PassManagerConfig but tailored for Clifford+T. Currently it subclasses PassManagerConfig as Clifford+T compilation pipeline (not changed in this PR) uses default layout, routing and scheduling stages. (Actually the only place which really needs this to be a subclass is DefaultRoutingPassManager which calls SabreSwapPassManager, which assumes that config includes layout_method. And I did not want to explicitly add layout_method to PassManagerCliffordTConfig as per previous discussions we might want to completely change how layout and routing look for Clifford+T compilations).

  • PassManagerCliffordTStagePlugin, which is analogous to PassManagerCliffordTStagePlugin, but tailored for Clifford+T compilation.

Both of the above classes are internal for now (not exposed in the documentation on purpose) since we might want to further refactor them when the PBC compilation pipeline will be added.

@alexanderivrii alexanderivrii requested a review from a team as a code owner March 30, 2026 21:09
@qiskit-bot
Copy link
Copy Markdown
Collaborator

One or more of the following people are relevant to this code:

  • @Qiskit/terra-core

@alexanderivrii alexanderivrii added this to the 2.5.0 milestone Mar 30, 2026
@alexanderivrii alexanderivrii added Changelog: Added Add an "Added" entry in the GitHub Release changelog. fault tolerance related to fault tolerance compilation labels Mar 30, 2026
@alexanderivrii alexanderivrii requested a review from Cryoris March 30, 2026 21:10
Comment on lines +177 to +178
rz_synthesis_error: float | None = None,
rz_cache_error: float | None = 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 expect this to go under the umbrella of generic synthesis arguments. Once we add a plugin here we'll need to accommodate for this, plus other synthesis methods might handle caching differently. Could we just call this rz_synthesis_config and make it a generic dictionary to pass into the synthesis method?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

That was mainly to show that we now can add Clifford+T pipeline-specific arguments (and because you have asked for this for comparing against other tools). But I agree that we need to think a bit more about how synthesis and Clifford+T should look.

Copy link
Copy Markdown
Collaborator

@Cryoris Cryoris left a comment

Choose a reason for hiding this comment

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

Some high level comments, I didn't read the logic yet 🙂

Comment thread qiskit/transpiler/passmanager_config.py Outdated
Comment on lines +185 to +187
basis_gates (list): List of basis gate names to unroll to.
coupling_map (CouplingMap): Directed graph representing a coupling
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.

Could we ditch these and just use a Target instead? Or is there a reason to use these as standalone?

Copy link
Copy Markdown
Member Author

@alexanderivrii alexanderivrii Apr 6, 2026

Choose a reason for hiding this comment

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

In theory, we can, however I am personally so used to generate preset pass managers while specifying basis_gates and coupling_map manually, that I would miss this functionality. However, based on our offline discussion, I have removed backend as an argument (especially that we have no such backends at the moment).

Comment thread qiskit/transpiler/preset_passmanagers/generate_preset_pass_manager.py Outdated
Comment thread qiskit/transpiler/preset_passmanagers/generate_preset_pass_manager.py Outdated
@Cryoris Cryoris moved this from Ready to In development in Qiskit 2.5 Apr 15, 2026
@Cryoris Cryoris self-assigned this Apr 16, 2026
Copy link
Copy Markdown
Collaborator

@Cryoris Cryoris left a comment

Choose a reason for hiding this comment

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

I took a closer look and overall this looks good. I left some, mostly minor comments, below. I didn't re-run the benchmarks since this doesn't touch the pipeline itself.

Comment on lines -1055 to -1056
if pass_manager_config.routing_method != "none":
split_2q_unitaries_swap = True
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 is because the routing method cannot be set and is always the default method, right?

rz_synthesis_error: float | None = None,
rz_cache_error: float | None = None,
):
r"""Generate a Clifford+T :class:`~.PassManager`
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

Suggested change
r"""Generate a Clifford+T :class:`~.PassManager`
r"""Generate a preset Clifford+T :class:`.StagedPassManager`.

):
r"""Generate a Clifford+T :class:`~.PassManager`

This function provides a fast and convenient way to construct a preset pass manager for
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 guess every way is "fast" since there's no computation done 😄

Suggested change
This function provides a fast and convenient way to construct a preset pass manager for
This function provides a convenient way to construct a preset pass manager for



def generate_preset_clifford_t_pass_manager(
optimization_level=2,
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.

Could we add typehints to all these arguments?

:class:`~.StagedPassManager` for. By default optimization level 2
is used if this is not specified. This can be 0, 1, 2, or 3. Higher
levels generate potentially more optimized circuits, at the expense
of longer transpilation time:
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.

Can we ensure to use compilation and transpilation consistently? So far we've been talking about compilation in the docstring, which I think makes sense due to the RZ->T step.

qc.rz(theta, 0)

# testing approximation_degree
for eps in 10.0 ** np.arange(-2, -13, -1):
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.

How long do these run? We could just run a few values here, we don't need to run every one 🙂

Comment on lines +324 to +326
unitary_synthesis_method (str): The name of the unitary synthesis
method to use. By default ``'default'`` is used. You can see a list of
installed plugins with :func:`.unitary_synthesis_plugin_names`.
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
unitary_synthesis_method (str): The name of the unitary synthesis
method to use. By default ``'default'`` is used. You can see a list of
installed plugins with :func:`.unitary_synthesis_plugin_names`.
unitary_synthesis_method (str): The name of the unitary synthesis
method to use. By default ``'default'`` is used. You can see a list of
installed plugins with :func:`.unitary_synthesis_plugin_names`.
Note that, while this is supported, it is encouraged to not synthesize
arbitrary unitaries in this fashion due to high T count and no available
cache.

features_transpiler:
- |
Added a new function :func:`~.generate_preset_clifford_t_pass_manager`, which provides
a fast and convenient way to construct a preset pass manager for Clifford+T compilation.
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
a fast and convenient way to construct a preset pass manager for Clifford+T compilation.
a convenient way to construct a preset pass manager for Clifford+T compilation.


For example::

from qiskit.transpiler.preset_passmanagers import generate_preset_clifford_t_pass_manager
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.

Can we make this available on qiskit.transpiler?

Comment on lines +17 to +18
basis_gates = ["cx", "s", "sdg", "h", "t", "tdg"]
pass_manager = generate_preset_clifford_t_pass_manager(basis_gates=basis_gates, optimization_level=3)
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 suggest this example to not set the basis gates specifically, one of the nice things here is that we don't have to do that anymore. Instead maybe just show compiling a simple circuit and counting the gates?

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

Labels

Changelog: Added Add an "Added" entry in the GitHub Release changelog. fault tolerance related to fault tolerance compilation

Projects

Status: In development

Development

Successfully merging this pull request may close these issues.

3 participants