Skip to content

✨ Add decompose-multi-controlled pass for multi-controlled X/Z decomposition#1810

Open
simon1hofmann wants to merge 14 commits into
mainfrom
decompose-multi-controlled-gates
Open

✨ Add decompose-multi-controlled pass for multi-controlled X/Z decomposition#1810
simon1hofmann wants to merge 14 commits into
mainfrom
decompose-multi-controlled-gates

Conversation

@simon1hofmann

@simon1hofmann simon1hofmann commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

Description

  • Add a decompose-multi-controlled QCO pass that decomposes multi-controlled Pauli-X and Pauli-Z gates (qco.ctrl with a single qco.x or qco.z body) into h, t, tdg, p, and cx using the Huang–Palsberg (PLDI 2024) no-ancilla algorithm (adapted from Qiskit synth_mcx_noaux_hp24).
  • MCZ uses the HP24 core directly (algebraically MCZ = H·MCX·H, with redundant Hadamard bookends canceled for k ≥ 2).
  • Expose via mqt-cc --decompose-multi-controlled and QuantumCompilerConfig::enableDecomposeMultiControlled (opt-in, default off).
  • min-controls option (default 2) keeps single-control gates (CX, CZ) intact; configurable via mqt-cc --decompose-multi-controlled-min-controls.

Usage

# Decompose CCX/CCZ and larger MCX/MCZ (default min-controls=2)
mqt-cc --decompose-multi-controlled input.mlir -o output.mlir

# Keep Toffoli/CCZ native; decompose only 3+ controls
mqt-cc --decompose-multi-controlled \
       --decompose-multi-controlled-min-controls=3 \
       input.mlir -o output.mlir

AI Assistance

Used Composer 2.5 via Cursor for parts of this change. I reviewed the full
diff and take responsibility for everything in this PR.

Checklist

  • The pull request only contains commits that are focused and relevant to this change.
  • I have added appropriate tests that cover the new/changed functionality.
  • I have updated the documentation to reflect these changes.
  • I have added entries to the changelog for any noteworthy additions, changes, fixes, or removals.
  • I have added migration instructions to the upgrade guide (if needed).
  • The changes follow the project's style guidelines and introduce no new warnings.
  • The changes are fully tested and pass the CI checks.
  • I have reviewed my own code changes.

If PR contains AI-assisted content:

  • I have disclosed the use of AI tools in the PR description as per our AI Usage Guidelines.
  • AI-assisted commits include an Assisted-by: [Model Name] via [Tool Name] footer.
  • I confirm that I have personally reviewed and understood all AI-generated content, and accept full responsibility for it.

@simon1hofmann simon1hofmann self-assigned this Jun 24, 2026
@simon1hofmann simon1hofmann added enhancement Improvement of existing feature c++ Anything related to C++ code MLIR Anything related to MLIR labels Jun 24, 2026
@simon1hofmann simon1hofmann added this to the MLIR Support milestone Jun 24, 2026
…criptions in test_multi_controlled_decomposition.cpp to reflect the one- vs two-ancilla boundary.
@codecov

codecov Bot commented Jun 24, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 99.73753% with 1 line in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
...nsforms/Decomposition/DecomposeMultiControlled.cpp 96.8% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

@simon1hofmann

Copy link
Copy Markdown
Contributor Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Jun 24, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Full review finished.

@coderabbitai

coderabbitai Bot commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Adds a configurable pass that decomposes multi-controlled X/Z qco.ctrl operations into one- and two-qubit gates, exposes it through the compiler pipeline and CLI, and expands tests and build wiring for the new behavior.

Changes

Multi-controlled gate decomposition pass

Layer / File(s) Summary
Public contracts and pass definition
mlir/include/mlir/Compiler/CompilerPipeline.h, mlir/include/mlir/Dialect/QCO/Transforms/Decomposition/MultiControlled.h, mlir/include/mlir/Dialect/QCO/Transforms/Passes.td, CHANGELOG.md, pyproject.toml
QuantumCompilerConfig gains decomposition settings, the synthesis header declares synthesizeMcx/synthesizeMcz, TableGen defines decompose-multi-controlled, and the changelog plus typo allowlist are updated.
HP24 synthesis implementation
mlir/lib/Dialect/QCO/Transforms/Decomposition/MultiControlled.cpp
Implements the MCX and MCZ synthesis helpers, including wire tracking, dirty-ancilla routines, relative-phase construction, the HP24 core, and the public entry points.
Pass rewrite and pipeline wiring
mlir/lib/Dialect/QCO/Transforms/Decomposition/DecomposeMultiControlled.cpp, mlir/lib/Compiler/CompilerPipeline.cpp, mlir/tools/mqt-cc/mqt-cc.cpp, mlir/lib/Dialect/QCO/Transforms/CMakeLists.txt
DecomposeMultiControlled matches qualifying qco.ctrl ops, the compiler pipeline inserts it when enabled after validating min-controls, the CLI exposes the new flags, and the transforms library gets project options.
Build and test coverage
mlir/unittests/Dialect/QCO/Transforms/Decomposition/CMakeLists.txt, mlir/unittests/Compiler/test_compiler_pipeline.cpp, mlir/unittests/Dialect/QCO/Transforms/Decomposition/test_multi_controlled_decomposition.cpp
The new decomposition test target is built, the compiler pipeline tests thread the enable flag, and the new gtests cover DD equivalence, smoke cases, edge cases, and death tests.

Sequence Diagram(s)

sequenceDiagram
  participant mqt-cc
  participant QuantumCompilerConfig
  participant QuantumCompilerPipeline as QuantumCompilerPipeline::runPipeline
  participant DecomposeMultiControlled as DecomposeMultiControlled pass
  participant synthesizeMcx
  participant synthesizeMcz

  mqt-cc->>QuantumCompilerConfig: set enableDecomposeMultiControlled and min-controls
  QuantumCompilerPipeline->>QuantumCompilerConfig: validate min-controls >= 2
  QuantumCompilerPipeline->>DecomposeMultiControlled: createDecomposeMultiControlled(options)
  DecomposeMultiControlled->>synthesizeMcx: rewrite qco.ctrl with qco.x body
  DecomposeMultiControlled->>synthesizeMcz: rewrite qco.ctrl with qco.z body
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested labels

feature

Suggested reviewers

  • burgholzer

Poem

A bunny hopped through qubit snow,
Where X and Z learned how to split and grow.
With twinkly phases, snip-snap, neat,
The controls now dance on smaller feet.
🐇✨ Hoppy gates and tidy trails!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 11.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and accurately summarizes the main change: adding a pass to decompose multi-controlled X/Z gates.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description check ✅ Passed The PR description follows the template, includes summary, usage, AI disclosure, and a completed checklist, with only the optional issue footer omitted.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch decompose-multi-controlled-gates

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@mlir/lib/Compiler/CompilerPipeline.cpp`:
- Around line 150-154: The `runPipeline` setup in `QuantumCompilerPipeline`
should validate `config_.decomposeMultiControlledMinControls` before any stages
mutate the module, instead of relying on `qco::createDecomposeMultiControlled`
to reject bad values later. Add an upfront config check alongside the other
early validations in `runPipeline`, using the `enableDecomposeMultiControlled` /
`decomposeMultiControlledMinControls` fields, and fail fast before Stage 1 if
the value is below 2.

In `@mlir/lib/Dialect/QCO/Transforms/Decomposition/McxSynthesis.cpp`:
- Around line 461-462: Clarify the one-dirty-ancilla branch in
McxSynthesis::decompose so the condition matches the comment’s “22+ controls”
wording and the parity-sensitive logic is unambiguous. Update the check on n to
explicitly reflect the intended control-count threshold in the dirty-ancilla
selection path, and keep the branch condition aligned with the surrounding
synthesis helpers so future cleanup does not invert the rule by mistake.

In `@mlir/unittests/Compiler/test_compiler_pipeline.cpp`:
- Around line 259-265: The CompilerPipelineTest end-to-end coverage only
exercises the X-path in DecomposeMultiControlledPass, so add a second
integration case for the Z-path using mlir::qc::multipleControlledZ. Update the
test fixture in test_compiler_pipeline.cpp by following the same pattern as the
existing runPipeline call and assert the MCZ pipeline behavior through the same
QCProgramBuilder::build and CompilationRecord flow. Keep the new case alongside
the current DecomposeMultiControlledPass coverage so both multipleControlledX
and multipleControlledZ are validated through the QC→QCO→optimization pipeline.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 83afc255-d120-40bc-8ed5-582fe1000e54

📥 Commits

Reviewing files that changed from the base of the PR and between 4065349 and dff6eeb.

📒 Files selected for processing (12)
  • CHANGELOG.md
  • mlir/include/mlir/Compiler/CompilerPipeline.h
  • mlir/include/mlir/Dialect/QCO/Transforms/Decomposition/MultiControlled.h
  • mlir/include/mlir/Dialect/QCO/Transforms/Passes.td
  • mlir/lib/Compiler/CompilerPipeline.cpp
  • mlir/lib/Dialect/QCO/Transforms/Decomposition/DecomposeMultiControlled.cpp
  • mlir/lib/Dialect/QCO/Transforms/Decomposition/McxSynthesis.cpp
  • mlir/tools/mqt-cc/mqt-cc.cpp
  • mlir/unittests/Compiler/test_compiler_pipeline.cpp
  • mlir/unittests/Dialect/QCO/Transforms/Decomposition/CMakeLists.txt
  • mlir/unittests/Dialect/QCO/Transforms/Decomposition/test_multi_controlled_decomposition.cpp
  • pyproject.toml

Comment thread mlir/lib/Compiler/CompilerPipeline.cpp
Comment thread mlir/lib/Dialect/QCO/Transforms/Decomposition/McxSynthesis.cpp Outdated
Comment thread mlir/unittests/Compiler/test_compiler_pipeline.cpp Outdated
@simon1hofmann

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 24, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
mlir/unittests/Compiler/test_compiler_pipeline.cpp (1)

259-281: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Disable unrelated Stage 5 passes in these decomposition checks.

Both tests treat any afterQCOCanon != afterOptimization diff as proof that multi-controlled decomposition ran, but runPipeline(..., false, false, false, true, ...) still leaves MergeSingleQubitRotationGates enabled. That means an unrelated Stage 5 change could keep these tests green even if DecomposeMultiControlled regresses.

Suggested fix
-  runPipeline(module.get(), false, false, false, true, record);
+  runPipeline(module.get(), false, true, false, true, record);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@mlir/unittests/Compiler/test_compiler_pipeline.cpp` around lines 259 - 281,
The decomposition tests in CompilerPipelineTest are currently too permissive
because runPipeline still enables an unrelated Stage 5 pass, so a change in
MergeSingleQubitRotationGates could make the afterQCOCanon versus
afterOptimization comparison pass even if multi-controlled decomposition fails.
Update DecomposeMultiControlledPass and DecomposeMultiControlledPassMcz to run
with only the decomposition-relevant pipeline enabled, or otherwise disable the
Stage 5 rotation-merge path in runPipeline for these checks, so the EXPECT_NE
assertion specifically validates DecomposeMultiControlled and the
multipleControlledX/multipleControlledZ cases.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@mlir/unittests/Compiler/test_compiler_pipeline.cpp`:
- Around line 283-297: The test currently only checks that
QuantumCompilerPipeline::runPipeline fails, which still allows the rejection to
happen later in DecomposeMultiControlled after earlier stages have run. Update
CompilerPipelineTest.RejectsDecomposeMultiControlledMinControlsBelowTwo to also
assert that CompilationRecord::afterQCImport remains empty when
decomposeMultiControlledMinControls is below two, so the preflight validation is
enforced before Stage 1 or any intermediate records are produced.

In
`@mlir/unittests/Dialect/QCO/Transforms/Decomposition/test_multi_controlled_decomposition.cpp`:
- Around line 378-404: The two “untouched” tests only verify that one
multi-controlled op remains, so they can miss regressions where the surviving
operation changes kind; update McxDecompositionTest::LeavesMultiOpCtrlUntouched
and McxDecompositionTest::LeavesMultiControlledHUntouched to assert the
preserved op is still the expected CtrlOp/MCH form and that its body is
unchanged after runDecomposePass, using the existing QCOProgramBuilder setup and
countMultiControlledOps as a secondary check only.

---

Outside diff comments:
In `@mlir/unittests/Compiler/test_compiler_pipeline.cpp`:
- Around line 259-281: The decomposition tests in CompilerPipelineTest are
currently too permissive because runPipeline still enables an unrelated Stage 5
pass, so a change in MergeSingleQubitRotationGates could make the afterQCOCanon
versus afterOptimization comparison pass even if multi-controlled decomposition
fails. Update DecomposeMultiControlledPass and DecomposeMultiControlledPassMcz
to run with only the decomposition-relevant pipeline enabled, or otherwise
disable the Stage 5 rotation-merge path in runPipeline for these checks, so the
EXPECT_NE assertion specifically validates DecomposeMultiControlled and the
multipleControlledX/multipleControlledZ cases.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: f9c18476-abd2-4d99-94d9-f4385100f19b

📥 Commits

Reviewing files that changed from the base of the PR and between dff6eeb and b2f30eb.

📒 Files selected for processing (5)
  • mlir/lib/Compiler/CompilerPipeline.cpp
  • mlir/lib/Dialect/QCO/Transforms/CMakeLists.txt
  • mlir/lib/Dialect/QCO/Transforms/Decomposition/MultiControlled.cpp
  • mlir/unittests/Compiler/test_compiler_pipeline.cpp
  • mlir/unittests/Dialect/QCO/Transforms/Decomposition/test_multi_controlled_decomposition.cpp

Comment thread mlir/unittests/Compiler/test_compiler_pipeline.cpp
@simon1hofmann

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 24, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@simon1hofmann simon1hofmann requested a review from burgholzer June 24, 2026 20:56
@mergify mergify Bot added the conflict label Jun 24, 2026
Signed-off-by: simon1hofmann <119581649+simon1hofmann@users.noreply.github.com>
@mergify mergify Bot added conflict and removed conflict labels Jun 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

c++ Anything related to C++ code conflict enhancement Improvement of existing feature MLIR Anything related to MLIR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant