Skip to content

Conversation

@marcelwa
Copy link
Contributor

@marcelwa marcelwa commented Dec 9, 2025

Description

This pull request refactors the dynamic device library loading API to return the newly created device object, improving usability and clarity in both C++ and Python bindings. The changes ensure that when a dynamic device library is loaded, the caller immediately receives a usable device handle, simplifying subsequent backend creation and session management.

API and Binding Improvements

  • The return type of addDynamicDeviceLibrary in qdmi::Driver was changed from void to QDMI_Device, so it now returns a pointer to the newly loaded device instead of just performing the action. (include/mqt-core/qdmi/Driver.hpp, src/qdmi/Driver.cpp) [1] [2]
  • The Python binding for add_dynamic_device_library was updated to return a Device object, with documentation and usage examples reflecting the new return value for easier backend creation. (bindings/fomac/fomac.cpp, python/mqt/core/fomac.pyi) [1] [2] [3] [4]

Device Construction and Usability

  • Added a static factory method fromQDMIDevice to the Session::Device class, allowing creation of a Device object from a raw device handle, which is necessary for bindings where direct token construction is not accessible. (include/mqt-core/fomac/FoMaC.hpp)

Testing

  • Added a new test to verify that addDynamicDeviceLibrary returns a valid device pointer and that the device is usable, improving reliability and regression coverage. (test/qdmi/test_driver.cpp)

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.

@marcelwa marcelwa requested a review from Copilot December 9, 2025 14:01
@marcelwa marcelwa self-assigned this Dec 9, 2025
@marcelwa marcelwa added usability Anything related to usability c++ Anything related to C++ code QDMI Anything related to QDMI labels Dec 9, 2025
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR refactors the dynamic device library loading API to return the newly created Device object instead of void, improving usability by allowing callers to immediately obtain a device handle for backend creation.

Key changes:

  • Modified addDynamicDeviceLibrary to return QDMI_Device instead of void
  • Added Session::Device::fromQDMIDevice factory method for creating Device objects from raw handles
  • Updated Python bindings to return Device objects with improved documentation and usage examples

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated no comments.

Show a summary per file
File Description
include/mqt-core/qdmi/Driver.hpp Updated addDynamicDeviceLibrary signature to return QDMI_Device and added documentation for the return value
src/qdmi/Driver.cpp Implemented return of newly created device pointer from addDynamicDeviceLibrary
include/mqt-core/fomac/FoMaC.hpp Added fromQDMIDevice static factory method to enable Device construction from raw handles in bindings
bindings/fomac/fomac.cpp Updated Python binding to capture and return Device object using the new factory method
python/mqt/core/fomac.pyi Updated type stub with new return type and enhanced documentation with usage examples
test/qdmi/test_driver.cpp Added test verifying the function returns a valid, usable device pointer

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@codecov
Copy link

codecov bot commented Dec 9, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 9, 2025

📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • The add_dynamic_device_library function now returns a device handle that can be directly used for backend creation, streamlining the workflow.
  • Tests

    • Added tests to verify the returned device handle functionality.

✏️ Tip: You can customize this high-level summary in your review settings.

Walkthrough

The pull request modifies add_dynamic_device_library across the QDMI Driver, FoMaC bindings, and Python bindings to return a device handle instead of void. A new factory method fromQDMIDevice is added to enable device construction from QDMI handles, and corresponding tests verify the return value is non-null and valid.

Changes

Cohort / File(s) Summary
Documentation
CHANGELOG.md
Added entry documenting the new feature: device handle returned from add_dynamic_device_library.
QDMI Core API
include/mqt-core/qdmi/Driver.hpp, src/qdmi/Driver.cpp
Changed addDynamicDeviceLibrary return type from void to QDMI_Device; implementation returns devices_.back().get() after emplacing new device.
FoMaC Headers & Bindings
include/mqt-core/fomac/FoMaC.hpp, bindings/fomac/fomac.cpp
Added [[nodiscard]] factory method Device::fromQDMIDevice(QDMI_Device) for binding contexts; updated C++ binding to capture and return device via factory method instead of void call.
Python Bindings
python/mqt/core/fomac.pyi
Updated add_dynamic_device_library signature to return Device instead of None; added docstring sections and usage examples demonstrating device assignment and backend creation.
Tests
test/qdmi/test_driver.cpp
Added DynamicDeviceLibraryTest.addDynamicDeviceLibraryReturnsDevice test verifying returned device handle is non-null and queryable.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Areas requiring attention:
    • Consistency of return value propagation across all layers (QDMI → FoMaC → Python)
    • Correctness of Device::fromQDMIDevice factory method and its Token default initialization
    • Test coverage ensures device handle validity (pointer non-null, properties queryable)
    • Python binding docstring and example accuracy

Possibly related PRs

  • PR #1355: Modifies the same addDynamicDeviceLibrary code paths in FoMaC bindings and QDMI Driver, directly related refactoring.

Suggested labels

enhancement, python

Suggested reviewers

  • burgholzer
  • ystade

Poem

🐰 A library loaded, a device in hand!
No void returns in this promised land,
From QDMI depths through FoMaC gates,
The handle returns—backends await! ✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title concisely describes the main change: making Device instantiable from dynamic QDMI device libraries, which is the core refactoring purpose.
Description check ✅ Passed The PR description is comprehensive and well-structured, following the template with clear sections including motivation, technical changes, and API improvements with reference links.
✨ 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 qdmi-device-library-usability

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.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 9, 2025

📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • add_dynamic_device_library now returns a Device object, enabling direct device usage immediately after creation. This streamlines your device initialization workflow by eliminating additional setup steps.
  • Tests

    • Added test coverage to verify proper device creation and property access from dynamic device libraries.

✏️ Tip: You can customize this high-level summary in your review settings.

Walkthrough

The return type of add_dynamic_device_library is changed from void to fomac::Session::Device across the C++ implementation, Python bindings, and test suite. A new static factory method Device::fromQDMIDevice() is added to construct Device objects from QDMI device handles, enabling the bindings to return the created device directly.

Changes

Cohort / File(s) Change Summary
Core API Updates
include/mqt-core/qdmi/Driver.hpp, src/qdmi/Driver.cpp
Driver::addDynamicDeviceLibrary() return type changed from void to QDMI_Device; implementation now returns the newly created device handle via devices_.back().get().
Device Factory & C++ Bindings
include/mqt-core/fomac/FoMaC.hpp, bindings/fomac/fomac.cpp
New public static factory method Device::fromQDMIDevice(QDMI_Device) added to construct Device objects; binding function return type updated from void to fomac::Session::Device with proper return value construction.
Python Type Stub
python/mqt/core/fomac.pyi
Function signature updated to return Device instead of None; docstring refined to document return value and usage patterns.
Tests
test/qdmi/test_driver.cpp
New test DynamicDeviceLibraryTest.addDynamicDeviceLibraryReturnsDevice verifies non-null device return and confirms device properties are queryable.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Verify return value propagation through the stack: Driver::addDynamicDeviceLibrary()Device::fromQDMIDevice() → Python binding
  • Confirm new factory method correctly wraps the existing Token-based constructor with default Token
  • Check test coverage completeness and assertions
  • Validate Python type stub consistency with C++ implementation

Possibly related PRs

Suggested labels

enhancement, minor, python

Suggested reviewers

  • ystade
  • burgholzer

Poem

A device returned at last!
No more void calls of the past, 🐰
The function now speaks true,
Returns what it's designed to do,
From QDMI up the stack we go,
Let the factory methods flow! ✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: enabling instantiation of Device objects from dynamic QDMI device libraries, which is the core objective of this refactoring.
Description check ✅ Passed The description covers the main changes, motivation, affected files, and includes a checklist template, though no checklist items are marked as completed.
✨ 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 qdmi-device-library-usability

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: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1597298 and fd7619e.

📒 Files selected for processing (6)
  • bindings/fomac/fomac.cpp (2 hunks)
  • include/mqt-core/fomac/FoMaC.hpp (1 hunks)
  • include/mqt-core/qdmi/Driver.hpp (1 hunks)
  • python/mqt/core/fomac.pyi (2 hunks)
  • src/qdmi/Driver.cpp (1 hunks)
  • test/qdmi/test_driver.cpp (1 hunks)
🧰 Additional context used
🧠 Learnings (6)
📓 Common learnings
Learnt from: burgholzer
Repo: munich-quantum-toolkit/core PR: 1355
File: src/qdmi/sc/Device.cpp:97-102
Timestamp: 2025-12-07T09:10:31.820Z
Learning: In the munich-quantum-toolkit/core repository, duplication of QDMI-related macros (such as IS_INVALID_ARGUMENT) across device implementations (e.g., in src/qdmi/sc/Device.cpp and src/qdmi/dd/Device.cpp) is acceptable as a temporary measure. The preferred long-term solution is to upstream these macros to the QDMI repository rather than creating local shared headers, so they can be reused across all dependent projects.
Learnt from: burgholzer
Repo: munich-quantum-toolkit/core PR: 1287
File: test/qdmi/dd/error_handling_test.cpp:118-194
Timestamp: 2025-11-05T07:42:45.507Z
Learning: In the munich-quantum-toolkit/core QDMI device API, session parameters can only be set before calling `device_session_init()`. Once a session is initialized, any attempt to set a parameter returns `QDMI_ERROR_BADSTATE`. Since `SessionGuard` (in test/qdmi/dd/helpers/test_utils.hpp) automatically initializes the session in its constructor, tests that need to verify session parameter setting behavior before initialization must allocate a separate uninitialized session rather than reusing the `SessionGuard`'s session.
Learnt from: marcelwa
Repo: munich-quantum-toolkit/core PR: 1243
File: test/python/qdmi/qiskit/test_qdmi_qiskit_backend.py:0-0
Timestamp: 2025-11-04T14:28:32.371Z
Learning: In the munich-quantum-toolkit/core repository, at least one FoMaC device is always available during testing, so skip logic for missing devices in QDMI Qiskit backend tests is not necessary.
📚 Learning: 2025-12-07T09:10:31.820Z
Learnt from: burgholzer
Repo: munich-quantum-toolkit/core PR: 1355
File: src/qdmi/sc/Device.cpp:97-102
Timestamp: 2025-12-07T09:10:31.820Z
Learning: In the munich-quantum-toolkit/core repository, duplication of QDMI-related macros (such as IS_INVALID_ARGUMENT) across device implementations (e.g., in src/qdmi/sc/Device.cpp and src/qdmi/dd/Device.cpp) is acceptable as a temporary measure. The preferred long-term solution is to upstream these macros to the QDMI repository rather than creating local shared headers, so they can be reused across all dependent projects.

Applied to files:

  • include/mqt-core/fomac/FoMaC.hpp
  • include/mqt-core/qdmi/Driver.hpp
📚 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:

  • include/mqt-core/fomac/FoMaC.hpp
  • include/mqt-core/qdmi/Driver.hpp
  • src/qdmi/Driver.cpp
  • bindings/fomac/fomac.cpp
  • test/qdmi/test_driver.cpp
📚 Learning: 2025-10-17T11:09:50.147Z
Learnt from: marcelwa
Repo: munich-quantum-toolkit/core PR: 1243
File: test/python/qdmi/qiskit/test_qdmi_qiskit_site_handling.py:162-173
Timestamp: 2025-10-17T11:09:50.147Z
Learning: For QDMI tests that reference a specific named device via fixture (e.g., "MQT NA Default QDMI Device"), it is acceptable to hard-code device-specific values such as zone counts and indices, as these tests are intentionally coupled to that device's structure and serve as structural invariant checks.

Applied to files:

  • include/mqt-core/fomac/FoMaC.hpp
  • test/qdmi/test_driver.cpp
📚 Learning: 2025-11-04T14:28:32.371Z
Learnt from: marcelwa
Repo: munich-quantum-toolkit/core PR: 1243
File: test/python/qdmi/qiskit/test_qdmi_qiskit_backend.py:0-0
Timestamp: 2025-11-04T14:28:32.371Z
Learning: In the munich-quantum-toolkit/core repository, at least one FoMaC device is always available during testing, so skip logic for missing devices in QDMI Qiskit backend tests is not necessary.

Applied to files:

  • include/mqt-core/fomac/FoMaC.hpp
📚 Learning: 2025-11-05T07:42:45.507Z
Learnt from: burgholzer
Repo: munich-quantum-toolkit/core PR: 1287
File: test/qdmi/dd/error_handling_test.cpp:118-194
Timestamp: 2025-11-05T07:42:45.507Z
Learning: In the munich-quantum-toolkit/core QDMI device API, session parameters can only be set before calling `device_session_init()`. Once a session is initialized, any attempt to set a parameter returns `QDMI_ERROR_BADSTATE`. Since `SessionGuard` (in test/qdmi/dd/helpers/test_utils.hpp) automatically initializes the session in its constructor, tests that need to verify session parameter setting behavior before initialization must allocate a separate uninitialized session rather than reusing the `SessionGuard`'s session.

Applied to files:

  • include/mqt-core/qdmi/Driver.hpp
  • bindings/fomac/fomac.cpp
  • test/qdmi/test_driver.cpp
🧬 Code graph analysis (5)
python/mqt/core/fomac.pyi (5)
include/mqt-core/fomac/FoMaC.hpp (1)
  • Device (614-614)
src/qdmi/dd/Device.cpp (1)
  • Device (149-151)
include/mqt-core/na/fomac/Device.hpp (1)
  • Device (88-88)
src/na/fomac/Device.cpp (1)
  • Device (579-580)
python/mqt/core/na/fomac.pyi (1)
  • Device (17-114)
include/mqt-core/qdmi/Driver.hpp (1)
test/qdmi/test_driver.cpp (1)
  • config (52-60)
src/qdmi/Driver.cpp (2)
include/mqt-core/qdmi/Driver.hpp (1)
  • libName (447-450)
test/qdmi/test_driver.cpp (1)
  • config (52-60)
bindings/fomac/fomac.cpp (2)
src/qdmi/dd/Device.cpp (2)
  • get (152-158)
  • get (152-152)
test/qdmi/test_driver.cpp (1)
  • config (52-60)
test/qdmi/test_driver.cpp (2)
src/qdmi/sc/Device.cpp (2)
  • get (50-56)
  • get (50-50)
src/qdmi/Driver.cpp (2)
  • QDMI_device_query_device_property (513-521)
  • QDMI_device_query_device_property (513-516)
🪛 Cppcheck (2.18.0)
src/qdmi/Driver.cpp

[information] Limiting analysis of branches. Use --check-level=exhaustive to analyze all branches.

(normalCheckLevelMaxBranches)

⏰ 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). (2)
  • GitHub Check: 🐍 Test (macos-15-intel) / 🐍 macos-15-intel
  • GitHub Check: 🐍 Test (windows-2022) / 🐍 windows-2022
🔇 Additional comments (5)
include/mqt-core/fomac/FoMaC.hpp (1)

615-624: LGTM! Factory method provides clean binding-oriented construction.

The static factory correctly uses the existing private constructor pattern. Consider whether a null-check on the device parameter is needed here or if it's intentionally left to callers/downstream code.

src/qdmi/Driver.cpp (1)

388-395: LGTM! Clean implementation returning the new device handle.

The implementation correctly returns the raw pointer from the newly emplaced device. The lifetime is properly managed by the Driver singleton's devices_ vector.

include/mqt-core/qdmi/Driver.hpp (1)

440-450: LGTM! API change is well-documented.

The updated signature and documentation clearly communicate the new return value. Existing callers can safely ignore the return value if they don't need it, maintaining backward compatibility.

python/mqt/core/fomac.pyi (1)

300-341: LGTM! Type stub and documentation properly updated.

The return type, docstring, and example all correctly reflect the new behavior of returning a Device object that can be used directly to create backends.

bindings/fomac/fomac.cpp (1)

243-258: LGTM! Binding correctly wraps the QDMI device handle.

The implementation properly captures the returned QDMI_Device and wraps it using the new fromQDMIDevice factory. The lack of null-check is acceptable since addDynamicDeviceLibrary throws std::runtime_error on failure (per the documented contract in Driver.hpp), ensuring qdmiDevice is non-null on successful return.

Copy link
Member

@burgholzer burgholzer left a comment

Choose a reason for hiding this comment

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

This looks great to me.
A Changelog entry would probably be justified.

@marcelwa marcelwa enabled auto-merge December 9, 2025 16:08
@marcelwa marcelwa merged commit c6e28c6 into main Dec 9, 2025
34 checks passed
@marcelwa marcelwa deleted the qdmi-device-library-usability branch December 9, 2025 16:19
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 QDMI Anything related to QDMI usability Anything related to usability

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants