Skip to content

Conversation

@alexanderivrii
Copy link
Member

Summary

Addresses #15452.

This PR replaces CommutativeCancellation by CommutativeOptimization in the default compilation pipeline for continuous basis sets, which is relevant for optimization levels 2 and 3. This should provide higher quality results at similar runtimes.

Since this is an important change, we did not want to do it late in 2.3, but it would be nice to do it early for 2.4, so that we have a sufficient time to test the impact.

Details and Comments:

We do not want to apply this change for Clifford+T transpilation, since we need to fully rethink that pipeline, and this is tracked independently in #15457.

@alexanderivrii alexanderivrii added this to the 2.4.0 milestone Dec 18, 2025
@alexanderivrii alexanderivrii requested a review from a team as a code owner December 18, 2025 08:24
@alexanderivrii alexanderivrii added the mod: transpiler Issues and PRs related to Transpiler label Dec 18, 2025
@qiskit-bot
Copy link
Collaborator

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

  • @Qiskit/terra-core

@alexanderivrii alexanderivrii changed the title Comm opt in transpiler pipeline Add CommutativeOptimization to transpiler pipeline Dec 18, 2025
@coveralls
Copy link

coveralls commented Dec 22, 2025

Pull Request Test Coverage Report for Build 21170921342

Warning: This coverage report may be inaccurate.

This pull request's base commit is no longer the HEAD commit of its target branch. This means it includes changes from outside the original pull request, including, potentially, unrelated coverage changes.

Details

  • 3 of 3 (100.0%) changed or added relevant lines in 1 file are covered.
  • 703 unchanged lines in 14 files lost coverage.
  • Overall coverage decreased (-0.007%) to 87.925%

Files with Coverage Reduction New Missed Lines %
crates/qasm2/src/lex.rs 2 92.54%
crates/transpiler/src/passes/commutation_cancellation.rs 2 90.17%
qiskit/synthesis/two_qubit/xx_decompose/decomposer.py 2 89.23%
crates/circuit/src/parameter/symbol_expr.rs 3 73.04%
crates/cext/src/transpiler/passes/unitary_synthesis.rs 7 89.17%
crates/circuit/src/dag_circuit.rs 10 85.29%
crates/synthesis/src/discrete_basis/solovay_kitaev.rs 13 80.47%
crates/circuit/src/packed_instruction.rs 26 93.51%
crates/synthesis/src/euler_one_qubit_decomposer.rs 36 91.31%
crates/transpiler/src/transpiler.rs 36 94.01%
Totals Coverage Status
Change from base Build 21139795452: -0.007%
Covered Lines: 100104
Relevant Lines: 113851

💛 - Coveralls

@alexanderivrii
Copy link
Member Author

I have slightly changed the order of the passes in the default optimization pass manager for optimization_level=2,3: now CommutativeOptimization runs before Optimize1qGatesDecomposition.

The previous order when optimization_level=2 was:

  • remove identity equiv
  • optimize 1q
  • commutative optimization
  • (optional) basis translator
  • fixed point check

There was one example where this got stuck in an infinite loop with the basis set ["rz", "sx"] when the circuit had two consecutive SX-gates:

  • commutative optimization merged the two consecutive SX gates into RX
  • basis translator rewrote RX as RZ, SX, RZ, SX, RZ
  • remove identity equivs removed the inner RZ gate
  • the size and the depth of the circuit wobbled a bit, and the fixed point pass used in optimization level=2 (unlike minimum point pass in level 3) was not able to determine convergence

With the new order, optimize1q brings the circuit to the desired basis, the optional basis translator is no longer needed, and no "wobbling" happens.

Regardless of the problematic example above, I believe that applying CommutativeOptimization before Optimize1q also makes sense in general.

@alexanderivrii
Copy link
Member Author

I have rebased this pass on top of main and locally run the full suite of ASV benchmarks.

Regarding performance. Except for the benchmarks mentioned previously in this comment, there was nothing else statistically significant.

Regarding quality of the output circuit. There are actually two family of benchmarks where the depth has increased:

  • In QUEKOTranspilerBench.track_depth_bntf_optimal_depth_25 the depth changed from 211 to 327
  • In UtilityScaleBenchmarks.track_qft_depth the depth changed from 2692 to 2815

In both cases the change is due not to interchanging the order of Optimize1qGatesDecomposition and CommutativeOptimization, but to the intrinsic randomness of Sabre during transpilation. In other words, the default transpiler seed chosen in the benchmarks favors the main branch. Running each of the two benchmarks 1000 times each with different random seeds (ranging from 0 to 999) gives the following:

QFT:

  • main: average 2-qubit count: 11596, average 2-qubit depth: 2753
  • this PR: average 2-qubit count: 11579, average 2-qubit depth: 2742

QUEKO:

  • main: average CX-count: 439, average RZ-count: 892, average depth: 242
  • this PR: average CX-count: 440, average RZ-count: 896, average depth: 246

There is no statistical difference on these benchmarks.

@Cryoris Cryoris added the Changelog: New Feature Include in the "Added" section of the changelog label Jan 20, 2026
@Cryoris Cryoris self-assigned this Jan 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Changelog: New Feature Include in the "Added" section of the changelog mod: transpiler Issues and PRs related to Transpiler

Projects

Status: Ready

Development

Successfully merging this pull request may close these issues.

5 participants