Skip to content

Conversation

@taminob
Copy link
Collaborator

@taminob taminob commented Sep 16, 2025

Description

TODO

Related to #1122

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.

@taminob taminob self-assigned this Sep 16, 2025
@taminob taminob force-pushed the taminob/mlir-two-qubit-gate-decomposition-pass branch from d7f49cc to 4bc6f15 Compare October 22, 2025 17:22
@taminob taminob force-pushed the taminob/mlir-two-qubit-gate-decomposition-pass branch from c4f6399 to ffb96f3 Compare November 18, 2025 13:36
@taminob taminob force-pushed the taminob/mlir-two-qubit-gate-decomposition-pass branch from 2e3a48f to f5ae2b0 Compare November 20, 2025 12:07
@codecov
Copy link

codecov bot commented Nov 20, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@taminob taminob force-pushed the taminob/mlir-two-qubit-gate-decomposition-pass branch 3 times, most recently from bbcec1e to 49d512f Compare November 21, 2025 16:15
@taminob
Copy link
Collaborator Author

taminob commented Nov 21, 2025

@coderabbitai review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 21, 2025

✅ Actions performed

Review triggered.

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
Copy link
Contributor

coderabbitai bot commented Nov 21, 2025

📝 Walkthrough

Walkthrough

A new gate decomposition pass is added to the MLIR MQTOpt dialect. The implementation includes pass declaration, Weyl-based two-qubit decomposition pattern logic, utility helpers for MLIR/quantum operations, CMake integration with Eigen dependency, and comprehensive MLIR tests.

Changes

Cohort / File(s) Change Summary
Build system & dependencies
CMakeLists.txt, mlir/lib/Dialect/MQTOpt/Transforms/CMakeLists.txt
Added FetchContent for remote Eigen dependency (tag 3.4.1) and linked Eigen3::Eigen library to MLIRMQTOptTransforms target.
Pass API declarations
mlir/include/mlir/Dialect/MQTOpt/Transforms/Passes.h, mlir/include/mlir/Dialect/MQTOpt/Transforms/Passes.td
Declared new populateGateDecompositionPatterns function and GateDecomposition pass definition with summary describing various gate decompositions.
Pass implementation
mlir/lib/Dialect/MQTOpt/Transforms/GateDecomposition.cpp
Implemented GateDecomposition class with runOnOperation override that initializes patterns, configures greedy rewrite strategy, and applies decompositions to operations.
Decomposition pattern & logic
mlir/lib/Dialect/MQTOpt/Transforms/GateDecompositionPattern.cpp
Implemented GateDecompositionPattern with Weyl-based two-qubit decomposition framework including matrix operations, Euler basis support, series handling, and gate synthesis for UnitaryInterface operations.
Utility helpers
mlir/lib/Dialect/MQTOpt/Transforms/Helpers.h
Introduced helper utilities for MLIR value conversion, parameter extraction, qubit classification, and linear-algebra operations (Kronecker product, eigendecomposition, unitarity checks).
Test coverage
mlir/test/Dialect/MQTOpt/Transforms/gate-decomposition.mlir
Added comprehensive MLIR test module covering identity cancellation, CNOT reduction, decomposition patterns, and complex gate series with FileCheck assertions.

Sequence Diagram

sequenceDiagram
    participant Pass as GateDecomposition Pass
    participant Pattern as GateDecompositionPattern
    participant Decomposer as TwoQubitBasisDecomposer
    participant Rewriter as PatternRewriter
    
    Pass->>Pass: runOnOperation()
    Pass->>Pass: Create RewritePatternSet
    Pass->>Pattern: populateGateDecompositionPatterns()
    Pattern->>Pass: Register pattern
    
    Pass->>Pass: Configure GreedyRewriteConfig
    loop For each Operation (top-down)
        Pass->>Pattern: matchAndRewrite(UnitaryInterface op)
        alt Pattern Matches
            Pattern->>Decomposer: create() + twoQubitDecompose()
            Decomposer->>Decomposer: Weyl decomposition
            Decomposer->>Decomposer: Generate gate sequence
            Decomposer-->>Pattern: Return TwoQubitSeries
            Pattern->>Pattern: applySeries() - replace + validate
            Pattern->>Rewriter: Emit new operations
            Rewriter-->>Pass: Update IR
        else No Match
            Pattern-->>Pass: Skip operation
        end
    end
    
    alt Success
        Pass->>Pass: Pass succeeded
    else Failure
        Pass->>Pass: Signal pass failure
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Areas requiring extra attention:

  • mlir/lib/Dialect/MQTOpt/Transforms/GateDecompositionPattern.cpp — High-density mathematical logic including Weyl decomposition, complex matrix operations (diagonalization, Kronecker products, canonical forms), and correctness of gate synthesis algorithms.
  • mlir/lib/Dialect/MQTOpt/Transforms/Helpers.h — Extensive template utilities and inline implementations (eigendecomposition, matrix conversions, type inference) that require careful validation of correctness and edge case handling.
  • Integration & consistency — Ensure proper data flow between GateDecomposition pass, GateDecompositionPattern, and Helpers utilities; verify that MLIR type handling and pattern application align.
  • mlir/test/Dialect/MQTOpt/Transforms/gate-decomposition.mlir — Verify test coverage is sufficient for diverse decomposition scenarios (identity cancellation, odd CNOT counts, blocked series, three+ basis gates) and that CHECK patterns are robust.

Suggested labels

feature, c++, MLIR

Suggested reviewers

  • burgholzer

Poem

🐰 A rabbit hops through quantum gates so fine,
Decomposing two-qubit unitary design,
With Weyl and Euler bases in array,
Patterns match and rewrite the day,
Eigen's matrices help gates align! 🎯✨

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Description check ⚠️ Warning The description is incomplete and mostly contains placeholder text ('TODO'), with only a related issue reference. Multiple required checklist items are unchecked and no actual description content is provided. Replace 'TODO' with a comprehensive description of the change, motivation, and dependencies. Complete the checklist items by addressing documentation, changelog, and style guidelines, or explicitly check/uncheck applicable items with justification.
Docstring Coverage ⚠️ Warning Docstring coverage is 37.88% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: implementing a two-qubit gate decomposition pass, which is the core feature of this pull request.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch taminob/mlir-two-qubit-gate-decomposition-pass

Tip

📝 Customizable high-level summaries are now available in beta!

You can now customize how CodeRabbit generates the high-level summary in your pull requests — including its content, structure, tone, and formatting.

  • Provide your own instructions using the high_level_summary_instructions setting.
  • Format the summary however you like (bullet lists, tables, multi-section layouts, contributor stats, etc.).
  • Use high_level_summary_in_walkthrough to move the summary from the description to the walkthrough section.

Example instruction:

"Divide the high-level summary into five sections:

  1. 📝 Description — Summarize the main change in 50–60 words, explaining what was done.
  2. 📓 References — List relevant issues, discussions, documentation, or related PRs.
  3. 📦 Dependencies & Requirements — Mention any new/updated dependencies, environment variable changes, or configuration updates.
  4. 📊 Contributor Summary — Include a Markdown table showing contributions:
    | Contributor | Lines Added | Lines Removed | Files Changed |
  5. ✔️ Additional Notes — Add any extra reviewer context.
    Keep each section concise (under 200 words) and use bullet or numbered lists for clarity."

Note: This feature is currently in beta for Pro-tier users, and pricing will be announced later.


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 and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 10

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b35d7be and 4ea6f02.

📒 Files selected for processing (8)
  • CMakeLists.txt (1 hunks)
  • mlir/include/mlir/Dialect/MQTOpt/Transforms/Passes.h (1 hunks)
  • mlir/include/mlir/Dialect/MQTOpt/Transforms/Passes.td (1 hunks)
  • mlir/lib/Dialect/MQTOpt/Transforms/CMakeLists.txt (1 hunks)
  • mlir/lib/Dialect/MQTOpt/Transforms/GateDecomposition.cpp (1 hunks)
  • mlir/lib/Dialect/MQTOpt/Transforms/GateDecompositionPattern.cpp (1 hunks)
  • mlir/lib/Dialect/MQTOpt/Transforms/Helpers.h (1 hunks)
  • mlir/test/Dialect/MQTOpt/Transforms/gate-decomposition.mlir (1 hunks)
🧰 Additional context used
🧠 Learnings (5)
📓 Common learnings
Learnt from: DRovara
Repo: munich-quantum-toolkit/core PR: 1108
File: mlir/test/Dialect/MQTOpt/Transforms/lift-measurements.mlir:269-288
Timestamp: 2025-10-09T13:20:11.483Z
Learning: In the MQT MLIR dialect, the `rz` gate should not be included in the `DIAGONAL_GATES` set for the `ReplaceBasisStateControlsWithIfPattern` because its operator matrix does not have the required shape | 1 0 | / | 0 x | for the targets-as-controls optimization. It is only included in `LiftMeasurementsAboveGatesPatterns` where the matrix structure requirement differs.
Learnt from: DRovara
Repo: munich-quantum-toolkit/core PR: 1108
File: mlir/lib/Dialect/MQTOpt/Transforms/DeadGateEliminationPattern.cpp:42-45
Timestamp: 2025-10-09T13:28:29.237Z
Learning: In the MQTOpt MLIR dialect, linear types enforce single-use semantics where each qubit value can only be consumed once, preventing duplicate deallocations and making RAUW operations safe when replacing output qubits with corresponding input qubits in transformation patterns.
📚 Learning: 2025-10-09T13:20:11.483Z
Learnt from: DRovara
Repo: munich-quantum-toolkit/core PR: 1108
File: mlir/test/Dialect/MQTOpt/Transforms/lift-measurements.mlir:269-288
Timestamp: 2025-10-09T13:20:11.483Z
Learning: In the MQT MLIR dialect, the `rz` gate should not be included in the `DIAGONAL_GATES` set for the `ReplaceBasisStateControlsWithIfPattern` because its operator matrix does not have the required shape | 1 0 | / | 0 x | for the targets-as-controls optimization. It is only included in `LiftMeasurementsAboveGatesPatterns` where the matrix structure requirement differs.

Applied to files:

  • mlir/include/mlir/Dialect/MQTOpt/Transforms/Passes.td
  • mlir/test/Dialect/MQTOpt/Transforms/gate-decomposition.mlir
  • mlir/lib/Dialect/MQTOpt/Transforms/GateDecomposition.cpp
  • mlir/include/mlir/Dialect/MQTOpt/Transforms/Passes.h
  • mlir/lib/Dialect/MQTOpt/Transforms/Helpers.h
  • mlir/lib/Dialect/MQTOpt/Transforms/GateDecompositionPattern.cpp
📚 Learning: 2025-10-09T13:28:29.237Z
Learnt from: DRovara
Repo: munich-quantum-toolkit/core PR: 1108
File: mlir/lib/Dialect/MQTOpt/Transforms/DeadGateEliminationPattern.cpp:42-45
Timestamp: 2025-10-09T13:28:29.237Z
Learning: In the MQTOpt MLIR dialect, linear types enforce single-use semantics where each qubit value can only be consumed once, preventing duplicate deallocations and making RAUW operations safe when replacing output qubits with corresponding input qubits in transformation patterns.

Applied to files:

  • mlir/test/Dialect/MQTOpt/Transforms/gate-decomposition.mlir
  • mlir/lib/Dialect/MQTOpt/Transforms/Helpers.h
📚 Learning: 2025-10-09T13:13:51.224Z
Learnt from: DRovara
Repo: munich-quantum-toolkit/core PR: 1108
File: mlir/lib/Dialect/MQTOpt/Transforms/ReplaceBasisStateControlsWithIfPattern.cpp:171-180
Timestamp: 2025-10-09T13:13:51.224Z
Learning: In MQT Core MLIR, UnitaryInterface operations guarantee 1-1 correspondence between input and output qubits in the same order. When cloning or modifying unitary operations (e.g., removing controls), this correspondence is maintained by construction, so yielding getAllInQubits() in else-branches matches the result types from the operation's outputs.

Applied to files:

  • mlir/test/Dialect/MQTOpt/Transforms/gate-decomposition.mlir
  • mlir/lib/Dialect/MQTOpt/Transforms/Helpers.h
  • mlir/lib/Dialect/MQTOpt/Transforms/GateDecompositionPattern.cpp
📚 Learning: 2025-11-03T23:09:26.881Z
Learnt from: burgholzer
Repo: munich-quantum-toolkit/core PR: 1287
File: test/qdmi/dd/CMakeLists.txt:9-21
Timestamp: 2025-11-03T23:09:26.881Z
Learning: The CMake functions `generate_device_defs_executable` and `generate_prefixed_qdmi_headers` used in QDMI device test CMakeLists.txt files are provided by the external QDMI library (fetched via FetchContent from https://github.com/Munich-Quantum-Software-Stack/qdmi.git), specifically in the cmake/PrefixHandling.cmake module of the QDMI repository.

Applied to files:

  • CMakeLists.txt
🪛 GitHub Check: 🇨‌ Lint / 🚨 Lint
mlir/lib/Dialect/MQTOpt/Transforms/GateDecompositionPattern.cpp

[warning] 1689-1689: mlir/lib/Dialect/MQTOpt/Transforms/GateDecompositionPattern.cpp:1689:30 [misc-include-cleaner]
no header providing "std::numeric_limits" is directly included


[warning] 929-929: mlir/lib/Dialect/MQTOpt/Transforms/GateDecompositionPattern.cpp:929:14 [misc-include-cleaner]
no header providing "Eigen::Vector" is directly included

⏰ Context from checks skipped due to timeout of 900000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: 🐍 Test (macos-14) / 🐍 macos-14
  • GitHub Check: 🐍 Test (ubuntu-24.04-arm) / 🐍 ubuntu-24.04-arm
  • GitHub Check: 🐍 Test (ubuntu-24.04) / 🐍 ubuntu-24.04
  • GitHub Check: 🐍 Test (windows-2022) / 🐍 windows-2022
  • GitHub Check: 🐉 Test / 🍎 macos-15-intel with LLVM@21
🔇 Additional comments (3)
mlir/lib/Dialect/MQTOpt/Transforms/CMakeLists.txt (1)

10-10: Confirm that Eigen3::Eigen is the correct target from your Eigen FetchContent setup

Linking against Eigen3::Eigen here is fine as long as the FetchContent configuration really defines that target on all supported toolchains; otherwise this will fail to configure or link in some environments. Please double‑check the Eigen CMake export to ensure the target name and namespace match what you use here (or add an alias/guard if necessary).

mlir/include/mlir/Dialect/MQTOpt/Transforms/Passes.h (1)

38-38: New pattern population hook looks consistent with existing transforms

The populateGateDecompositionPatterns(RewritePatternSet&) declaration fits cleanly alongside the other populate* helpers and matches the usage in GateDecomposition.cpp. Just make sure the implementation in GateDecompositionPattern.cpp is actually compiled into MLIRMQTOptTransforms so the call site links correctly.

mlir/lib/Dialect/MQTOpt/Transforms/GateDecompositionPattern.cpp (1)

460-540: Creation of GPhaseOp ignores potential control qubits.

When applying a series, the pattern adds a global phase gate via:

if (sequence.hasGlobalPhase()) {
  createOneParameterGate<GPhaseOp>(rewriter, location, sequence.globalPhase, {});
}

This always creates a GPhase with empty inQubits, even if the original series might have had controlled global phases. Given the dialect definition allows GPhaseOp to be controlled by qubits, this may drop control wiring when decomposing controlled global-phase structures. (mqt.readthedocs.io)

Please double‑check whether controlled GPhaseOps can appear in practice. If they can, you likely want to thread the relevant control qubits into the newly created GPhaseOp (and its types) instead of using an empty ValueRange.

⛔ Skipped due to learnings
Learnt from: DRovara
Repo: munich-quantum-toolkit/core PR: 1108
File: mlir/test/Dialect/MQTOpt/Transforms/lift-measurements.mlir:269-288
Timestamp: 2025-10-09T13:20:11.483Z
Learning: In the MQT MLIR dialect, the `rz` gate should not be included in the `DIAGONAL_GATES` set for the `ReplaceBasisStateControlsWithIfPattern` because its operator matrix does not have the required shape | 1 0 | / | 0 x | for the targets-as-controls optimization. It is only included in `LiftMeasurementsAboveGatesPatterns` where the matrix structure requirement differs.
Learnt from: DRovara
Repo: munich-quantum-toolkit/core PR: 1108
File: mlir/lib/Dialect/MQTOpt/Transforms/ReplaceBasisStateControlsWithIfPattern.cpp:171-180
Timestamp: 2025-10-09T13:13:51.224Z
Learning: In MQT Core MLIR, UnitaryInterface operations guarantee 1-1 correspondence between input and output qubits in the same order. When cloning or modifying unitary operations (e.g., removing controls), this correspondence is maintained by construction, so yielding getAllInQubits() in else-branches matches the result types from the operation's outputs.
Learnt from: burgholzer
Repo: munich-quantum-toolkit/core PR: 1283
File: src/qir/runtime/QIR.cpp:196-201
Timestamp: 2025-11-01T15:57:31.153Z
Learning: In the QIR runtime (src/qir/runtime/QIR.cpp), the PRX gate (__quantum__qis__prx__body) is an alias for the R gate (Phased X-Rotation) and should call runtime.apply<qc::R>(theta, phi, qubit), not runtime.apply<qc::RX>() which is a single-parameter rotation gate.

Copy link
Collaborator

@flowerthrower flowerthrower left a comment

Choose a reason for hiding this comment

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

Thank you @taminob for all your work. The math and logic appear to be correctly implemented. I loosely checked the expected K1, K2, ... decomposition values with a small debug script on my Mac and was able to reproduce (roughtly) the same values as the Qiskit decomposition.

The three remaining points are:

  1. Set up a proper test to automate exactly this verification process.
  2. Improve comments — just because the Rust implementation is poorly documented does not mean we should do the same.
    Especially since parts of your code are already nicely commented, it makes sense to extend this good style to the copied code.
  3. Revisit MLIR logic after dialect revamp

@taminob taminob force-pushed the taminob/mlir-two-qubit-gate-decomposition-pass branch 2 times, most recently from 7fc67db to 18cf6b0 Compare November 26, 2025 20:27
@taminob
Copy link
Collaborator Author

taminob commented Nov 27, 2025

I reworked the tests now (added unittests and made the MLIR tests more robust/less precise).

A couple of questions:

  • Is this approach to testing good now or do you think the MLIR tests are too imprecise?
  • Should I adjust this PR to also include the single-qubit decomposition in the pattern or should we do this in a follow-up PR? The full code already exists and it would be the most performant way to add the single-qubit decomposition in the same pass because the qubit series is collected anyway (although the pattern is quite big aleady).
  • The Windows ARM build has an internal alignment issue in Eigen (https://libeigen.gitlab.io/eigen/docs-nightly/group__TopicUnalignedArrayAssert.html; the link in the build log is broken). Will you resolve this issue already in the dialect rewrite that'll introduce Eigen?
  • I currently use two unsupported (so experimental) headers of Eigen. Is this fine or do we want to implement that ourselves? It's for kroneckerProduct() and Eigen::Matrix::exp()

@burgholzer
Copy link
Member

I reworked the tests now (added unittests and made the MLIR tests more robust/less precise).

A couple of questions:

  • Is this approach to testing good now or do you think the MLIR tests are too imprecise?

I just skimmed through both the lit tests and the unit tests and I think the overall direction is fine. I am pretty sure that I will have some more detailed comments when I check the PR in more detail.

  • Should I adjust this PR to also include the single-qubit decomposition in the pattern or should we do this in a follow-up PR? The full code already exists and it would be the most performant way to add the single-qubit decomposition in the same pass because the qubit series is collected anyway (although the pattern is quite big aleady).

Hm. multiple thoughts on this.
I foresee two different use cases for the synthesis routines here:

  • collection and resynthesis of arbitrary runs of two-qubit blocks with no real constraints on the gate set (maybe with a parameter that let's one choose the entangling gate; like CX or CZ or RZZ or ...)
  • synthesis of two-qubit operations (or blocks thereof) to a dedicated/native gateset of a divide (where only those operations are permitted in the decomposition).

These two might actually be more or less the same, the first might just be the second with some reasonable and relaxed defaults on the native gate-set.
I think it could make sense to include the single-qubit synthesis here as well because, as you said, the series are collected anyway, so one might as well apply this to those sequences in the same go.
The only concern that I would probably have is performance. I would assume that single-qubit synthesis is much more efficient than the two-qubit one. If all one does is two-qubit synthesis, then this might become costly at some point.

I am not quite sure that I follow this. That link says:

There are 4 known causes for this issue. If you can target [c++17] only with a recent compiler (e.g., GCC>=7, clang>=5, MSVC>=19.12), then you're lucky: enabling c++17 should be enough (if not, please report to us). Otherwise, please read on to understand those issues and learn how to fix them.

We are using more modern compilers than this (by far). The current CI runs report

-- The C compiler identification is MSVC 19.44.35217.0
-- The CXX compiler identification is MSVC 19.44.35217.0

This seems to indicate to me that you might need to dig a little deeper there.
I am not yet 100% sure if the first version of the dialect rewrite will immediately include the Eigen dependency. At the moment, the following signature is used in the unitary interface

InterfaceMethod<
            "Attempts to extract the static unitary matrix. "
            "Returns std::nullopt if the operation is symbolic or dynamic.",
            "DenseElementsAttr", "tryGetStaticMatrix", (ins)
        >,

An example of how that Attr is constructed would be

inline DenseElementsAttr getMatrixX(MLIRContext* ctx) {
  const auto& complexType = ComplexType::get(Float64Type::get(ctx));
  const auto& type = RankedTensorType::get({2, 2}, complexType);
  const auto& matrix = {0.0 + 0i, 1.0 + 0i,  // row 0
                        1.0 + 0i, 0.0 + 0i}; // row 1
  return DenseElementsAttr::get(type, matrix);
}

This might not be final yet; mostly because I still want to explore some options that might allow us to make the gates/gate matrices singletons and avoid repeated constructions of matrices for gates where this is definitely not necessary.

  • I currently use two unsupported (so experimental) headers of Eigen. Is this fine or do we want to implement that ourselves? It's for kroneckerProduct() and Eigen::Matrix::exp()

I am not too familiar with the details of Eigen, but just from the name alone, I have an aversion to using such headers. Is there any kind of intuition for how well these are tested/work/can be used?
Kronecker Product shouldn't be particularly hard to implement, I suppose.
The Matrix exponential certainly is a little more complicated.
This is definitely not a decision, but just a little bit of caution.

@taminob
Copy link
Collaborator Author

taminob commented Nov 28, 2025

I am not too familiar with the details of Eigen, but just from the name alone, I have an aversion to using such headers. Is there any kind of intuition for how well these are tested/work/can be used?
Kronecker Product shouldn't be particularly hard to implement, I suppose.
The Matrix exponential certainly is a little more complicated.
This is definitely not a decision, but just a little bit of caution.

The documentation of unsupported states:

This is the API documentation for Eigen's unsupported modules.

These modules are contributions from various users. They are provided "as is", without any support.

I think it might be mainly about the stability of the interfaces - so it could happen that different Eigen versions will break API/ABI. However, since they are user-provided, I guess it also heavily depends on the actual function to be used (see also this stackoverflow question.
Looking at the history of MatrixExponential.h, it has been a while since the last actual change, so I don't think that it is likely to have any functionality issues. Same for the KroneckerProduct.

I am not quite sure that I follow this. That link says:

There are 4 known causes for this issue. If you can target [c++17] only with a recent compiler (e.g., GCC>=7, clang>=5, MSVC>=19.12), then you're lucky: enabling c++17 should be enough (if not, please report to us). Otherwise, please read on to understand those issues and learn how to fix them.

We are using more modern compilers than this (by far). The current CI runs report

I'll look into it, although it's a bit hard on a different architecture. Could well be that it is caused by differences in alignment on ARM.

@taminob taminob force-pushed the taminob/mlir-two-qubit-gate-decomposition-pass branch 4 times, most recently from a9d1fc9 to 7efae47 Compare November 28, 2025 12:52
@taminob
Copy link
Collaborator Author

taminob commented Nov 28, 2025

I'll look into it, although it's a bit hard on a different architecture. Could well be that it is caused by differences in alignment on ARM.

Unfortunately, I couldn't really find the source of the error - also because I didn't manage to get a stacktrace in the CI and so can't really pinpoint the issue. I tried using C++23 stacktrace which did compile, but I didn't manage to override Eigen's eigen_assert at the place this is triggered. I didn't manage to reproduce this locally.

I think the cause might be one of https://libeigen.gitlab.io/eigen/docs-nightly/group__TopicPassingByValue.html or https://libeigen.gitlab.io/eigen/docs-nightly/group__TopicStlContainers.html (which should be fixed since C++11, but maybe LLVM+MSVC behaves buggy here - who knows) which are quite serious and need to be considered when using Eigen (at least I wasn't aware of it).

I'd suggest to simply set EIGEN_MAX_STATIC_ALIGN_BYTES to zero for ARM+Windows as advised in the documentation. The drawback is potentially non-optimal vectorization. I did this by defining EIGEN_DONT_ALIGN_STATICALLY.

@taminob taminob force-pushed the taminob/mlir-two-qubit-gate-decomposition-pass branch 2 times, most recently from 888deb2 to 7a80d30 Compare December 1, 2025 09:14
@taminob taminob force-pushed the taminob/mlir-two-qubit-gate-decomposition-pass branch from f45852b to c818f56 Compare December 20, 2025 11:01
@taminob taminob force-pushed the taminob/mlir-two-qubit-gate-decomposition-pass branch from b6c4301 to ce79ed2 Compare January 6, 2026 18:30
Comment on lines +228 to +242
auto traces = this->traces(targetDecomposition);
auto getDefaultNbasis = [&]() {
auto minValue = std::numeric_limits<fp>::min();
auto minIndex = -1;
for (int i = 0; std::cmp_less(i, traces.size()); ++i) {
// lower fidelity means it becomes easier to choose a lower number of
// basis gates
auto value = helpers::traceToFidelity(traces[i]) *
std::pow(actualBasisFidelity, i);
if (value > minValue) {
minIndex = i;
minValue = value;
}
}
return minIndex;
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

note to myself: check again, should probably be named maxValue/maxIndex and see if there is some llvm helper function for this

@mergify mergify bot added the conflict label Jan 16, 2026
@mergify mergify bot removed the conflict label Jan 21, 2026
@github-actions
Copy link
Contributor

github-actions bot commented Jan 21, 2026

Cpp-Linter Report ⚠️

Some files did not pass the configured checks!

clang-tidy (v21.1.8) reports: 9 concern(s)
  • mlir/lib/Passes/Patterns/GateDecompositionPattern.cpp:32:1: warning: [misc-include-cleaner]

    included header Arith.h is not used directly

       32 | #include <mlir/Dialect/Arith/IR/Arith.h>
          | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
       33 | #include <mlir/IR/MLIRContext.h>
  • mlir/lib/Passes/Patterns/GateDecompositionPattern.cpp:156:11: warning: [misc-include-cleaner]

    no header providing "llvm::errs" is directly included

       22 |     llvm::errs() << "Found series (" << series.complexity << "): ";
          |           ^
  • mlir/lib/Passes/Patterns/GateDecompositionPattern.cpp:409:9: warning: [readability-qualified-auto]

    'auto it2' can be declared as 'auto *it2'

      409 |         auto it2 = llvm::find(opInQubits, firstQubitIt != outQubits.end()
          |         ^~~~
          |         auto *
  • mlir/lib/Passes/Patterns/GateDecompositionPattern.cpp:505:41: warning: [misc-include-cleaner]

    no header providing "std::remove_cvref_t" is directly included

       41 |       if constexpr (std::is_same_v<std::remove_cvref_t<decltype(x)>,
          |                                         ^
  • mlir/unittests/decomposition/test_basis_decomposer.cpp:35:25: warning: [llvm-prefer-static-over-anonymous-namespace]

    function 'randomUnitaryMatrix' is declared in an anonymous namespace; prefer using 'static' for restricting visibility

       35 | [[nodiscard]] matrix4x4 randomUnitaryMatrix() {
          |                         ^
  • mlir/unittests/decomposition/test_basis_decomposer.cpp:50:25: warning: [llvm-prefer-static-over-anonymous-namespace]

    function 'canonicalGate' is declared in an anonymous namespace; prefer using 'static' for restricting visibility

       50 | [[nodiscard]] matrix4x4 canonicalGate(fp a, fp b, fp c) {
          |                         ^
  • mlir/unittests/decomposition/test_euler_decomposition.cpp:32:25: warning: [llvm-prefer-static-over-anonymous-namespace]

    function 'randomUnitaryMatrix' is declared in an anonymous namespace; prefer using 'static' for restricting visibility

       32 | [[nodiscard]] matrix2x2 randomUnitaryMatrix() {
          |                         ^
  • mlir/unittests/decomposition/test_weyl_decomposition.cpp:28:25: warning: [llvm-prefer-static-over-anonymous-namespace]

    function 'randomUnitaryMatrix' is declared in an anonymous namespace; prefer using 'static' for restricting visibility

       28 | [[nodiscard]] matrix4x4 randomUnitaryMatrix() {
          |                         ^
  • mlir/unittests/decomposition/test_weyl_decomposition.cpp:43:25: warning: [llvm-prefer-static-over-anonymous-namespace]

    function 'canonicalGate' is declared in an anonymous namespace; prefer using 'static' for restricting visibility

       43 | [[nodiscard]] matrix4x4 canonicalGate(fp a, fp b, fp c) {
          |                         ^

Have any feedback or feature suggestions? Share it here.

@taminob taminob added enhancement Improvement of existing feature c++ Anything related to C++ code MLIR Anything related to MLIR feature New feature or request and removed enhancement Improvement of existing feature labels Jan 24, 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 feature New feature or request MLIR Anything related to MLIR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants