Skip to content

Conversation

@Mostafa-Atallah2020
Copy link

@Mostafa-Atallah2020 Mostafa-Atallah2020 commented Nov 18, 2025

Summary

This PR adds a new transpiler pass ControlPatternSimplification that optimizes multi-controlled gates with complementary control patterns using Boolean algebraic simplification.

Note: This is an initial skeleton/draft PR. Full implementation will follow in subsequent commits.

Fixes #15348

Details and comments

Motivation

Multi-controlled gates with different control patterns can often be simplified when the patterns are complementary. For example, gates controlled on '11' and '01' both require q0=1, so they can be combined into a single gate controlled only on q0.

This pattern appears frequently in:

  • Hamiltonian simulation
  • Variational algorithms
  • Quantum walk circuits

As demonstrated in #15348, the transpiler currently produces 31 gates for a case that could be optimized to just 5 gates (520% overhead).

Optimization Techniques

The pass will support four main optimization strategies:

  1. Complementary patterns: (q0 ∧ q1) ∨ (q0 ∧ ¬q1) = q0

    • Example: ['11', '01'] → single control on q0
    • Reduces 2 multi-controlled gates to 1 single-controlled gate
  2. Subset patterns: (q0 ∧ q1 ∧ q2) ∨ (q0 ∧ q1 ∧ ¬q2) = (q0 ∧ q1)

    • Example: ['111', '110'] → reduces control count
    • Removes redundant control qubits
  3. XOR pairs: Patterns satisfying q1 ⊕ q2 = 1

    • Example: ['110', '101'] → CNOT-based optimization
    • Reduces 2 multi-controlled gates to 1 + 2 CNOTs
  4. Complete partitions: All control states covered

    • Example: ['00','01','10','11'] → unconditional gate
    • Eliminates all control qubits

Example Usage

from qiskit import QuantumCircuit
from qiskit.circuit.library import RXGate
from qiskit.transpiler.passes import ControlPatternSimplification

theta = np.pi / 4
qc = QuantumCircuit(3)
qc.append(RXGate(theta).control(2, ctrl_state='11'), [0, 1, 2])
qc.append(RXGate(theta).control(2, ctrl_state='01'), [0, 1, 2])

pass_ = ControlPatternSimplification()
optimized = pass_(qc)  # Result: Single CRX gate controlled by q0

Files Changed

  • qiskit/transpiler/passes/optimization/control_pattern_simplification.py - Main pass implementation (skeleton)
  • qiskit/transpiler/passes/optimization/__init__.py - Export pass
  • qiskit/transpiler/passes/__init__.py - Documentation and import
  • test/python/transpiler/test_control_pattern_simplification.py - Test skeleton

References

  • Atallah et al., "Graph Matching Trotterization for Continuous Time Quantum Walk Circuit Simulation", Proceedings of IEEE QCE 2025
  • Gonzalez et al., "Efficient sparse state preparation via quantum walks", npj Quantum Information (2025)
  • Amy et al., "Fast synthesis of depth-optimal quantum circuits", IEEE TCAD 32.6 (2013)
  • Shende & Markov, "On the CNOT-cost of TOFFOLI gates", arXiv:0803.2316 (2008)
  • Barenco et al., "Elementary gates for quantum computation", Phys. Rev. A 52.5 (1995)

Next Steps

  • Implement core optimization logic
  • Add comprehensive test cases
  • Benchmark against common use cases
  • Add release notes using reno

@Mostafa-Atallah2020 Mostafa-Atallah2020 requested a review from a team as a code owner November 18, 2025 23:02
@qiskit-bot qiskit-bot added the Community PR PRs from contributors that are not 'members' of the Qiskit repo label Nov 18, 2025
@qiskit-bot
Copy link
Collaborator

Thank you for opening a new pull request.

Before your PR can be merged it will first need to pass continuous integration tests and be reviewed. Sometimes the review process can be slow, so please be patient.

While you're waiting, please feel free to review other open PRs. While only a subset of people are authorized to approve pull requests for merging, everyone is encouraged to review open pull requests. Doing reviews helps reduce the burden on the core team and helps make the project's code better for everyone.

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

  • @Qiskit/terra-core

@CLAassistant
Copy link

CLAassistant commented Nov 18, 2025

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you all sign our Contributor License Agreement before we can accept your contribution.
1 out of 2 committers have signed the CLA.

✅ Mostafa-Atallah2020
❌ Mostafa Atallah


Mostafa Atallah seems not to be a GitHub user. You need a GitHub account to be able to sign the CLA. If you have already a GitHub account, please add the email address used for this commit to your account.
You have signed the CLA already but the status is still pending? Let us recheck it.

@Mostafa-Atallah2020
Copy link
Author

Hi @alexanderivrii, @Cryoris, and @debasmita2102 I totally removed the sympy dependency please rereview the PR

@Mostafa-Atallah2020
Copy link
Author

@Cryoris linters issue fixed

@coveralls
Copy link

Pull Request Test Coverage Report for Build 19681817322

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

  • 320 of 440 (72.73%) changed or added relevant lines in 3 files are covered.
  • 487 unchanged lines in 36 files lost coverage.
  • Overall coverage decreased (-0.04%) to 88.167%

Changes Missing Coverage Covered Lines Changed/Added Lines %
qiskit/transpiler/passes/optimization/control_pattern_simplification.py 318 438 72.6%
Files with Coverage Reduction New Missed Lines %
crates/cext/src/transpiler/transpile_layout.rs 1 99.33%
crates/circuit/src/dag_circuit.rs 1 84.52%
qiskit/circuit/library/generalized_gates/mcmt.py 1 87.64%
qiskit/circuit/library/standard_gates/rxx.py 1 96.67%
qiskit/circuit/library/standard_gates/rzx.py 1 96.67%
crates/circuit/src/parameter/symbol_expr.rs 2 73.35%
qiskit/circuit/library/standard_gates/rx.py 2 96.49%
qiskit/circuit/library/standard_gates/ryy.py 2 93.33%
qiskit/circuit/library/standard_gates/rzz.py 2 92.86%
qiskit/circuit/library/standard_gates/xx_minus_yy.py 2 93.75%
Totals Coverage Status
Change from base Build 19482567593: -0.04%
Covered Lines: 94676
Relevant Lines: 107382

💛 - Coveralls

@alexanderivrii
Copy link
Member

alexanderivrii commented Nov 28, 2025

I had a brief look at the PR (so no detailed feedback yet), honestly it's significantly more code than I expected. At this point I am wondering if it would be better to have this as a Qiskit-Community project and not a part of Qiskit itself, however I do want to look at the code in more detail and discuss with others before making a particular suggestion.

I have a few high-level questions (in no particular order):

  1. What is the difference between the complementary patterns and subset patterns, it seems that the former is a special case of the latter, right? Also, why the latter optimization is called "subset", we are still considering terms with exactly the same control bits, i.e. not the following case when the control bits of one term are a subset of the other: (q0 ∧ q1 ∧ q2) ∨ (q0 ∧ ¬q2)?

  2. When reasoning about reductions, shouldn't we use instead of , i.e. (q0 ∧ q1) ⊕ (q0 ∧ ¬q1) = q0instead of (q0 ∧ q1) ∨ (q0 ∧ ¬q1) = q0? Here both are correct, but more generally if the terms are not disjoint, the original circuit can apply the controlled gate twice while the simplified circuit cannot. Do you know of any reductions when the terms are not necessarily disjoint?

  3. Since this is application-driven (you mentioned quantum walks in the issue), what is the typical number of control qubits ? Realistically, do we expect to see about say at most 5 controls for each gate or hundreds? This has an effect of whether we can construct a truth table and you the already existing EsopGenerator code; @gadial, what do you think about this?

  4. The XOR pairs simplification is interesting, I did not know about this before, is there a reference for this? How did you originally plan to use sympy for this? Also the optimization can probably be generalized, for instance the following reduction is also valid:

q_0: ─────o──────────■─────
          │          │     
q_1: ─────o──────────■─────
          │          │     
q_2: ─────o──────────■─────
     ┌────┴────┐┌────┴────┐
q_3: ┤ Rx(0.1) ├┤ Rx(0.1) ├
     └─────────┘└─────────┘
                                    
q_0: ──■────■───────────────■────■──
     ┌─┴─┐  │               │  ┌─┴─┐
q_1: ┤ X ├──┼───────o───────┼──┤ X ├
     └───┘┌─┴─┐     │     ┌─┴─┐└───┘
q_2: ─────┤ X ├─────o─────┤ X ├─────
          └───┘┌────┴────┐└───┘     
q_3: ──────────┤ Rx(0.1) ├──────────
               └─────────┘          
  1. Have you thought about the complexity of your approach? From a brief look, it seemed that you are finding one reduction opportunity at a time while each time analyzing a quadratic number of pairs to consider, this will definitely become very slow if you have many long control patterns.

@Mostafa-Atallah2020
Copy link
Author

Hi @alexanderivrii,

Thank you for the detailed review. Here are my responses:

Complementary vs Subset Patterns: You're right that complementary patterns (Hamming distance 1) are a special case of subset patterns. I can consolidate these into a single detection method if preferred.

Boolean Logic & Double Application: The patterns represent mutually exclusive control states—no quantum state can match multiple patterns simultaneously, so there's no risk of double gate application.

Complexity: The typical use case involves 2-6 control qubits with 2-10 patterns (from quantum walk algorithms). The $O(n^2 \times m)$ bitwise approach, where $n$ is the number of patterns and $m$ is the number of control qubits, handles this efficiently. For edge cases, the implementation includes early termination, iterative reduction, and complete partition detection; pathological inputs return early rather than hanging.

XOR Optimization: The CX trick is documented in:

  • Atallah et al., "Graph Matching Trotterization for Continuous Time Quantum Walk Circuit Simulation" (IEEE QCE 2025)
  • Gonzalez et al., "Efficient sparse state preparation via quantum walks" (npj Quantum Information 2025)

SymPy Dependency: Completely removed—the implementation now uses pure bitwise operations.

Unit Test: I will add a test based on your 3-controlled RXs example.

Code Reduction: The current implementation (~1165 lines) can be reduced by ~30-40% by:

  • Merging _build_single_control_gate and _build_multi_control_gate
  • Consolidating _build_pairwise_optimized_gates and _build_iterative_pairwise_gates
  • Unifying xor_standard and xor_with_x with a flag
  • Removing unused _hamming_distance and duplicate code
  • Combining complementary and subset detection as you noted

@alexanderivrii
Copy link
Member

alexanderivrii commented Nov 30, 2025

Thanks @Mostafa-Atallah2020 for the answers, and I will take a look the above paper and your code (but in a week or so, after Qiskit 2.3 release). One question that you did not answer: would you have been even able to use sympy to find patterns that differ at two or more positions?

And a few more random questions, just by thinking about possible optimizations that one can perform.

  1. would you be able to simplify a circuit with the following 3 gates:
  • RZ(theta) controlled by x=0
  • RZ(theta) controlled by x=1 & y=0
  • RZ(theta) controlled by x=1 & y=1

Intuitively, the controls still form a complete partition.

  1. would you be able to simplify a circuit with the following 3 gates:
  • RZ(theta) controlled by x=0 & y=0
  • RZ(theta) controlled by x=1 & y=0
  • RZ(theta) controlled by x=1 & y=1

Here the complement of the involved patterns is a single pattern x=0 & y=1, so potentially you could reduce the 3 gates above to RZ(theta) controlled by x=0 & y=1 + some additional X-gates.

@Mostafa-Atallah2020
Copy link
Author

Hi @alexanderivrii,

Thank you for the suggestions. I've implemented both optimizations and added unit tests. Both the original SymPy-based version and the current bitwise implementation support all these optimizations.

Example 1: Mixed Control Counts

RZ(θ) controlled by x=0
RZ(θ) controlled by x=1 & y=0
RZ(θ) controlled by x=1 & y=1

This simplifies to unconditional RZ(θ) because:

x=0 OR (x=1 & y=0) OR (x=1 & y=1) = TRUE

Result: 3 gates → 1 gate. Unit test: test_mixed_control_counts_to_unconditional

Example 2: Complement Optimization

RZ(θ) controlled by x=0 & y=0  → pattern 00
RZ(θ) controlled by x=1 & y=0  → pattern 10
RZ(θ) controlled by x=1 & y=1  → pattern 11

Patterns [00, 10, 11] missing 01. This optimizes to:

RZ(θ)              # unconditional
RZ(-θ) ctrl=01     # cancels the missing pattern

Result: 3 gates → 2 gates. Unit test: test_complement_example_00_10_11

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

Labels

Community PR PRs from contributors that are not 'members' of the Qiskit repo

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Transpiler misses control pattern simplification

8 participants