Skip to content

🚚 Take ownership of the neutral-atom stack - #1111

Draft
denialhaag wants to merge 7 commits into
mainfrom
na-transfer
Draft

🚚 Take ownership of the neutral-atom stack#1111
denialhaag wants to merge 7 commits into
mainfrom
na-transfer

Conversation

@denialhaag

@denialhaag denialhaag commented Aug 16, 2026

Copy link
Copy Markdown
Member

Description

🤖 AI text below 🤖

This is the MQT QMAP side of moving the neutral-atom stack out of MQT Core (munich-quantum-toolkit/core#2092). QMAP is the only downstream consumer of the transferred code, so each piece is added here first and can then be removed from Core.

Four pieces move in:

  • The neutral-atom QDMI device configuration becomes MQT::QMapNAQDMIDeviceConfig under include/na/qdmi, together with the bundled device schema and its tests.
  • The neutral-atom computation model becomes MQT::QMapNAComputation under include/na/computation. nasp, zoned, and hybridmap now link that target instead of MQT::CoreNA, and no QMAP target depends on MQT::CoreNA anymore.
  • The neutral-atom FoMaC device session becomes MQT::QMapNAFoMaC under include/na/fomac.
  • AodOperation moves into hybridmap, which was its only consumer, so it no longer has to live in generic Core IR.

The neutral-atom QDMI device itself is deliberately left behind for now. Its implementation includes qdmi/common/DeviceConfiguration.hpp, which exists only on Core's main and not in the pinned v3.8.0, so the device cannot compile here until QMAP pins a Core release that ships it. The device tests and the FoMaC test are held back with it, since both need a registered neutral-atom QDMI device at runtime.

The Python bindings for mqt.core.na are not moved yet either. They bind na::Session::Device as deriving from fomac::Device, which Core registers in mqt.core.qdmi, so moving them requires wiring that base class across package boundaries.

Because the code is transferred rather than rewritten, FoMaC is added to the typos allowlist, matching the entry Core already carries.

AI notice

This PR and its contents were created with the assistance of Opus 5 via Claude Code.

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:

  • Any agent that created, edited, or submitted GitHub content was explicitly authorized for that scope, as required by our AI Usage Guidelines.
  • Every agent-authored or agent-edited public text body begins with the visible disclosure 🤖 *AI text below* 🤖 (titles are exempt).
  • I have disclosed AI assistance in the PR description.
  • I confirm that I have personally reviewed and understood all AI-generated content, and accept full responsibility for it.

Assisted-by: Opus 5 via Claude Code
Assisted-by: Opus 5 via Claude Code
Assisted-by: Opus 5 via Claude Code
Assisted-by: Opus 5 via Claude Code
@denialhaag denialhaag self-assigned this Aug 16, 2026
@github-project-automation github-project-automation Bot moved this to In Progress in MQT Compilation Aug 16, 2026
@denialhaag denialhaag added minor Changes leading to a minor version increase refactor Anything related to code refactoring labels Aug 16, 2026
Assisted-by: Opus 5 via Claude Code
Assisted-by: Opus 5 via Claude Code
@github-actions

github-actions Bot commented Aug 16, 2026

Copy link
Copy Markdown
Contributor

Cpp-Linter Report ⚠️

Some files did not pass the configured checks!

clang-tidy (v20.1.8) reports: 23 concern(s)
  • bindings/na/register_qdmi.cpp:57:23: warning: [misc-redundant-expression]

    both sides of overloaded operator are equivalent

       57 |   vector.def(nb::self == nb::self,
          |                       ^
  • bindings/na/register_qdmi.cpp:59:23: warning: [misc-redundant-expression]

    both sides of overloaded operator are equivalent

       59 |   vector.def(nb::self != nb::self,
          |                       ^
  • bindings/na/register_qdmi.cpp:75:21: warning: [misc-redundant-expression]

    both sides of overloaded operator are equivalent

       75 |   size.def(nb::self == nb::self,
          |                     ^
  • bindings/na/register_qdmi.cpp:77:21: warning: [misc-redundant-expression]

    both sides of overloaded operator are equivalent

       77 |   size.def(nb::self != nb::self,
          |                     ^
  • bindings/na/register_qdmi.cpp:86:23: warning: [misc-redundant-expression]

    both sides of overloaded operator are equivalent

       86 |   region.def(nb::self == nb::self,
          |                       ^
  • bindings/na/register_qdmi.cpp:88:23: warning: [misc-redundant-expression]

    both sides of overloaded operator are equivalent

       88 |   region.def(nb::self != nb::self,
          |                       ^
  • bindings/na/register_qdmi.cpp:104:24: warning: [misc-redundant-expression]

    both sides of overloaded operator are equivalent

      104 |   lattice.def(nb::self == nb::self,
          |                        ^
  • bindings/na/register_qdmi.cpp:106:24: warning: [misc-redundant-expression]

    both sides of overloaded operator are equivalent

      106 |   lattice.def(nb::self != nb::self,
          |                        ^
  • bindings/na/register_qdmi.cpp:137:23: warning: [misc-redundant-expression]

    both sides of overloaded operator are equivalent

      137 |   device.def(nb::self == nb::self,
          |                       ^
  • bindings/na/register_qdmi.cpp:139:23: warning: [misc-redundant-expression]

    both sides of overloaded operator are equivalent

      139 |   device.def(nb::self != nb::self,
          |                       ^
  • src/na/fomac/Device.cpp:97:10: warning: [modernize-use-trailing-return-type]

    use a trailing return type for this function

       97 |   size_t operator()(const Device::Vector& v) const {
          |   ~~~~~~ ^
          |   auto                                             -> size_t
  • src/na/qdmi/Configuration.cpp:266:22: warning: [modernize-use-trailing-return-type]

    use a trailing return type for this function

      266 | [[nodiscard]] Device parseAndValidate(const Json& json,
          |               ~~~~~~ ^
          |               auto
      267 |                                       const std::string_view source) {
          |                                                                      -> Device
  • src/na/qdmi/Configuration.cpp:434:23: warning: [modernize-use-trailing-return-type]

    use a trailing return type for this function

      434 | [[nodiscard]] int64_t checkedAdd(const int64_t left, const int64_t right) {
          |               ~~~~~~~ ^
          |               auto                                                        -> int64_t
  • src/na/qdmi/Configuration.cpp:442:23: warning: [modernize-use-trailing-return-type]

    use a trailing return type for this function

      442 | [[nodiscard]] int64_t checkedSubtract(const int64_t left, const int64_t right) {
          |               ~~~~~~~ ^
          |               auto                                                             -> int64_t
  • src/na/qdmi/Configuration.cpp:450:23: warning: [modernize-use-trailing-return-type]

    use a trailing return type for this function

      450 | [[nodiscard]] int64_t checkedMultiply(const int64_t left, const int64_t right) {
          |               ~~~~~~~ ^
          |               auto                                                             -> int64_t
  • src/na/qdmi/Configuration.cpp:476:1: warning: [modernize-use-trailing-return-type]

    use a trailing return type for this function

      475 | [[nodiscard]] std::pair<double, double>
          |               ~~~~~~~~~~~~~~~~~~~~~~~~~
          |               auto
      476 | solve2DLinearEquation(const int64_t x1, const int64_t x2, const int64_t y1,
          | ^
      477 |                       const int64_t y2, const int64_t x0, const int64_t y0) {
          |                                                                             -> std::pair<double, double>
  • src/na/qdmi/Configuration.cpp:483:55: warning: [clang-diagnostic-double-promotion]

    implicit conversion increases floating-point precision: 'const double' to 'long double'

      483 |   if (constexpr auto epsilon = 1e-10; std::abs(det) < epsilon) {
          |                                                     ~ ^~~~~~~
  • src/na/qdmi/Configuration.cpp:493:23: warning: [modernize-use-trailing-return-type]

    use a trailing return type for this function

      493 | [[nodiscard]] int64_t floorToInt64(const double value) {
          |               ~~~~~~~ ^
          |               auto                                     -> int64_t
  • src/na/qdmi/Configuration.cpp:504:23: warning: [modernize-use-trailing-return-type]

    use a trailing return type for this function

      504 | [[nodiscard]] int64_t coordinate(const int64_t origin, const int64_t offset,
          |               ~~~~~~~ ^
          |               auto
      505 |                                  const int64_t firstIndex,
      506 |                                  const int64_t firstVector,
      507 |                                  const int64_t secondIndex,
      508 |                                  const int64_t secondVector) {
          |                                                              -> int64_t
  • src/na/qdmi/Configuration.cpp:524:20: warning: [modernize-use-trailing-return-type]

    use a trailing return type for this function

      524 | [[nodiscard]] bool increment(std::vector<int64_t>& indices,
          |               ~~~~ ^
          |               auto
      525 |                              const std::vector<int64_t>& minima,
      526 |                              const std::vector<int64_t>& limits) {
          |                                                                  -> bool
  • src/na/qdmi/Configuration.cpp:542:22: warning: [modernize-use-trailing-return-type]

    use a trailing return type for this function

      542 | [[nodiscard]] Device readJSON(std::istream& is) {
          |               ~~~~~~ ^
          |               auto                              -> Device
  • src/na/qdmi/Configuration.cpp:556:8: warning: [modernize-use-trailing-return-type]

    use a trailing return type for this function

      556 | Device readJSON(const std::string_view json, const std::string_view source) {
          | ~~~~~~ ^
          | auto                                                                        -> Device
  • src/na/qdmi/Configuration.cpp:565:22: warning: [modernize-use-trailing-return-type]

    use a trailing return type for this function

      565 | [[nodiscard]] Device readJSON(const std::string& path) {
          |               ~~~~~~ ^
          |               auto                                     -> Device

Have any feedback or feature suggestions? Share it here.

Assisted-by: Opus 5 via Claude Code
@burgholzer

Copy link
Copy Markdown
Member

The neutral-atom QDMI device itself is deliberately left behind for now. Its implementation includes qdmi/common/DeviceConfiguration.hpp, which exists only on Core's main and not in the pinned v3.8.0, so the device cannot compile here until QMAP pins a Core release that ships it. The device tests and the FoMaC test are held back with it, since both need a registered neutral-atom QDMI device at runtime.

The Python bindings for mqt.core.na are not moved yet either. They bind na::Session::Device as deriving from fomac::Device, which Core registers in mqt.core.qdmi, so moving them requires wiring that base class across package boundaries.

Quite a bit of the code mentioned here has been backported to v3.x, so it can also be moved as part of this PR.

@denialhaag

Copy link
Copy Markdown
Member Author

The neutral-atom QDMI device itself is deliberately left behind for now. Its implementation includes qdmi/common/DeviceConfiguration.hpp, which exists only on Core's main and not in the pinned v3.8.0, so the device cannot compile here until QMAP pins a Core release that ships it. The device tests and the FoMaC test are held back with it, since both need a registered neutral-atom QDMI device at runtime.
The Python bindings for mqt.core.na are not moved yet either. They bind na::Session::Device as deriving from fomac::Device, which Core registers in mqt.core.qdmi, so moving them requires wiring that base class across package boundaries.

Quite a bit of the code mentioned here has been backported to v3.x, so it can also be moved as part of this PR.

Yes, I just didn't do that just yet because I didn't want the Python CI to be red. The upcoming PR in MQT Core will be fully independent of all of this. Once 3.9.0 is released and MQT QCEC is updated accordingly, I'll get this PR ready. 😌

@denialhaag

Copy link
Copy Markdown
Member Author

@burgholzer and @ystade, I have a quick question about whether (or how) the neutral-atom operations in na:: (that is, MQT Core's) and na::nalac:: should be consolidated. The operations belonging to the former use Location (aliasing double) and Atom, while the latter use Point (aliasing int64_t) and shared_ptr<Point>. Should I try consolidating them, or should they continue to coexist? 🤔

@ystade

ystade commented Aug 18, 2026

Copy link
Copy Markdown
Collaborator

As soon as NALAC causes any issues, feel free to remove it. I just kept it as a legacy but it is Kinds deprecated. Consolidating anything here with respect to NALAC is a warte of time.

@burgholzer

Copy link
Copy Markdown
Member

As soon as NALAC causes any issues, feel free to remove it. I just kept it as a legacy but it is Kinds deprecated. Consolidating anything here with respect to NALAC is a warte of time.

I think we do not need to remove it, necessarily. But what I take from your comment is that it is entirely fine to keep everything for NALAC self contained in its own directory and rather focus on a clean integration for the rest.

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

Labels

minor Changes leading to a minor version increase refactor Anything related to code refactoring

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants